首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用ReturnUrl设置状态参数中的不同Microsoft.Identity.Web

用ReturnUrl设置状态参数中的不同Microsoft.Identity.Web
EN

Stack Overflow用户
提问于 2021-09-17 14:48:05
回答 1查看 1.2K关注 0票数 2

我有一个ASP.NET核心web应用程序,它在使用Microsoft.Identity.Web的多租户配置中与Azure进行身份验证。我们使用租户/公司标识符作为应用程序URL的子域。(companyA.myapp.com,companyB.myapp.com)。有些用户可以访问应用程序的多个租户,因此我们不能将Azure AD租户直接映射到应用程序中的单个租户/公司。

对于Microsoft.Identity.Web,状态参数是如何设置或操作的,如本文所述?我想遵循这里提供的指导,但不知道从哪里开始。https://learn.microsoft.com/en-us/azure/active-directory/develop/reply-url#use-a-state-parameter

如果您有几个子域,并且您的场景要求在成功的身份验证之后,您将用户重定向到他们开始时所在的页面,使用状态参数可能会有帮助。在这一办法中:

  1. 为每个应用程序创建一个“共享”重定向URI,以处理从授权端点接收到的安全令牌。
  2. 您的应用程序可以在状态参数中发送特定于应用程序的参数(例如用户起源的子域URL或任何类似的品牌信息)。当使用状态参数时,防止RFC 6749第10.12节中规定的CSRF保护)。
  3. 特定于应用程序的参数将包括应用程序为用户提供正确体验所需的所有信息,即构造适当的应用程序状态。Azure AD授权端点从state参数中剥离HTML,因此确保没有在此参数中传递HTML内容。
  4. 当Azure AD向“共享”重定向URI发送响应时,它将将状态参数发送回应用程序。
  5. 然后,应用程序可以使用状态参数中的值来确定要进一步发送用户到的URL。确保您验证了CSRF保护。
EN

回答 1

Stack Overflow用户

发布于 2021-10-12 16:29:33

下面是我如何最终解决MS无限重定向与租户每个子域方案的问题。)试图想出一个更好的名字来解决这个问题。)

提供一个SigninRedirect控制器操作,该操作接受我们必须验证的returnUrl参数,以避免成为开放重定向。

将returnUrl设置为companyA.example.com/foo&bar=1的示例URL

代码语言:javascript
复制
https://signin.example.com/signin-redirect?returnUrl=companyA.example.com%2Ffoo%26bar%3D1
代码语言:javascript
复制
[Route("")]
public class SigninController : Controller
{
    private readonly IMediator _mediator;
    private readonly IConfiguration _configuration;
    public SigninController(IMediator mediator, IConfiguration configuration)
    {
        _mediator = mediator;
        _configuration = configuration;
    }
    [Authorize]
    [HttpGet("/signin-redirect")]
    public IActionResult SigninRedirect(string returnUrl)
    {
        string redirect;
        if (!string.IsNullOrEmpty(returnUrl) && IsValidSubdomainUrl(returnUrl))
        {
            redirect = returnUrl;
        }
        else
        {
            var appHost = _configuration.GetValue<string>("General:ApplicationHost");
            var home = new UriBuilder("https", appHost).Uri;
            return Redirect(home.AbsoluteUri);
        }
        return Redirect(redirect);
    }
    /// <summary>
    /// Avoid Open Redirect Vulnerability
    /// https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html
    /// </summary>
    /// <param name="returnUrl"></param>
    /// <returns></returns>
    private bool IsValidSubdomainUrl(string returnUrl)
    {
        var appHost = _configuration.GetValue<string>("General:ApplicationHost");
        var isValid = Uri.IsWellFormedUriString(returnUrl, UriKind.Absolute) &&
            Uri.TryCreate(returnUrl, UriKind.Absolute, out var uri) &&
            uri?.Host.EndsWith(appHost) == true;
        return isValid;
    }
}

在ConfigureServices(IServiceCollection服务)中,将cookies设置为跨所有子域共享,并配置一个OnRedirectToIdentityProvider事件,以便在用户尚未通过身份验证时重定向到您的签名URL:

代码语言:javascript
复制
var cookieDomain = _configuration.GetValue<string>("General:CookieDomain");

services.AddSession(options =>
{
    options.IdleTimeout = TimeSpan.FromDays(3);
    options.Cookie.Domain = cookieDomain;
    options.Cookie.Path = "/";
    options.Cookie.SameSite = SameSiteMode.Lax;
    options.Cookie.HttpOnly = true;
    options.Cookie.IsEssential = true;
});

services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(options =>
    {
        _configuration.Bind("AzureAd", options);
        options.Events ??= new OpenIdConnectEvents();
                        options.Events.OnRedirectToIdentityProvider += context => {
            var originalRequestUri = context.HttpContext.Request.GetUri();

            var signInHost = _configuration.GetValue<string>("General:SignInHost");
            var signInPath = _configuration.GetValue<string>("General:SignInUrl");

            if (!originalRequestUri.Host.Equals(signInHost, StringComparison.InvariantCultureIgnoreCase))
            {
                var signInUrl = QueryHelpers.AddQueryString(signInPath, "returnUrl", originalRequestUri.AbsoluteUri);

                // When on a subdomain and not authorized, then redirect to
                // our signin URL.
                context.Response.Redirect(signInUrl);

                // Let Microsoft.Identity.Web know that we already handled 
                // this redirect
                context.HandleResponse();
            }

            return Task.CompletedTask;
        };
    },
    cookieOptions => 
    {
        cookieOptions.Cookie.Domain = cookieDomain;
        cookieOptions.Cookie.Path = "/";
        cookieOptions.Cookie.SameSite = SameSiteMode.Lax;
    })
    .EnableTokenAcquisitionToCallDownstreamApi(new string[] { "user.read" })
    .AddDistributedTokenCaches();

services.ConfigureApplicationCookie(options =>
{
    options.Cookie.Domain = cookieDomain;
    options.Cookie.Name = ".AspNet.SharedCookie";
    options.Cookie.Path = "/";
    options.Cookie.SameSite = SameSiteMode.Lax;
});

定义的配置:

代码语言:javascript
复制
"General:CookieDomain": ".example.com",
"General:ApplicationHost": "example.com",
"General:SignInHost": "signin.example.com",
"General:SignInUrl": "https://signin.example.com/signin-redirect"

此外,您还需要使用来自AzureAd的常规用于Azure AD的Microsoft Docs配置部分。

代码语言:javascript
复制
"AzureAd:Instance": "https://login.microsoftonline.com/",
"AzureAd:Domain": "...",
"AzureAd:TenantId": "common",
"AzureAd:ClientId": "...",
"AzureAd:ClientSecret": "...",
"AzureAd:CallbackPath": "/signin-oidc",
"AzureAd:SignedOutCallbackPath": "/signout-callback-oidc",

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69225390

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档