【问题标题】:msal intercepting a redirect on client sidemsal 在客户端拦截重定向
【发布时间】:2021-03-22 06:07:28
【问题描述】:

将 Microsoft.Identity.Web 与 SPA 和 Vue 结合使用,并在控制器上使用 [AuthorizeWithScopes]

从某种意义上说,当缓存中的令牌过期时,我将获得 302 状态码并在响应标头中设置正确的位置以用于重定向,这在某种意义上是正确的。在响应标头上的浏览器网络选项卡中看到。

但我的问题只是......我似乎无法在客户端获得位置(尽管听起来很奇怪)。我试图拦截响应,但它不包含标头中的位置,它似乎事先失败了。

我试过了

   OnRedirectToIdentityProvider = context =>
 {
    if (ctx.Request.Path.StartsWithSegments("/api"))
   {
    if (ctx.Response.StatusCode == (int)HttpStatusCode.OK)
    {
        ctx.Response.StatusCode = 401;
    }

    context.HandleResponse();
}

return Task.CompletedTask;
}

但是上下文现在没有位置。只有当我删除 context.HandleResponse() 并让它通过时,我才能看到响应标头包含浏览器中的位置。当我尝试拦截客户端上的响应时,响应没有任何内容。我也遇到了 CORS 错误(这不是我能做的),但重点是设置 401,然后使用客户端的位置进行重定向(而不是从服务器端)。

有什么想法吗?

谢谢

【问题讨论】:

    标签: asp.net-core openid-connect msal jwt-auth


    【解决方案1】:

    我无法在 OnRedirectToIdentityProvider 中解决此问题,因为此时该位置不存在。只有在它尝试了重定向之后(而不是之前),它才会创建该位置。该位置包含用于进行身份验证的 microsoft.login 重定向 url。

    所以我的解决方案是在我们的 globalexceptionhandler 中间件中“捕获”重定向请求 (inspiration here)

    在我们的服务注册中:

    options.Events.OnRedirectToIdentityProvider = ctx =>
                    {
                        if (ctx.Request.Path.StartsWithSegments("/api", StringComparison.InvariantCulture))
                        {
                            if (ctx.Response.StatusCode == (int)HttpStatusCode.OK)
                            {
                                
                              // the context does not contain any location from headers at this point :(
                                ctx.Response.StatusCode = 401;
                                ctx.Properties.RedirectUri = ctx.Request.Headers["referer"]; // When RedirectUri is set here the location in the header will include it.
                                return Task.CompletedTask;
                            }
    
                            ctx.HandleResponse();
                        }
    
                        return Task.CompletedTask;
                    };
    

    GlobalExceptionMiddleware.cs 中的后端:

    public async Task InvokeAsync(HttpContext context, IEnumerable<IExceptionHandler> exceptionHandlers, IAuthorizedUserContext userContext)
            {
                try
                {
                    await _next(context).ConfigureAwait(false);
    
                    await HandleMsalUiRequiredException(context).ConfigureAwait(false);
                }
                // ..... catches for different types of exceptions
            }
    
            /// <summary>
            /// Handles 302 redirect to login provider requests when an invalid token (e.g. a cached token) is used.
            /// This method aborts the call to login from backend and sends the response to client for it to handle instead.
            /// </summary>
            /// <param name="context">The context.</param>
            private async Task HandleMsalUiRequiredException(HttpContext context)
            {
                if (context.Response.StatusCode == 302 && context.Response.Headers.ContainsKey("Location") && context.Request.Path.StartsWithSegments("/api", StringComparison.InvariantCulture))
                {
                    var message = $"Jwt token in cache is invalid for User: {context.User.Identity.Name}. Acquiring new token.";
                    var ex = new MsalUiRequiredException("401", message);
                    _logger.LogWarning(ex, message);
                    await WriteHttpErrorResult(context, ex, HttpStatusCode.Unauthorized, ex.Message).ConfigureAwait(false);
                }
            }
    

    对传入响应的前端拦截(使用 axios/vue、typescript 和 nswag 生成的客户端):

    protected transformResult(url: string, response: AxiosResponse, processor: (response: AxiosResponse) => any) {
           
           // Intercept msal jwt cache authorization error and then
           // acquire a new token by redirecting to login which will redirect back to user's current location.
           if (response.status === 401 && response.data.ExceptionType === 'Microsoft.Identity.Client.MsalUiRequiredException' && response.headers['location'] !== null)
            {
                window.location.href = response.headers['location'];
            }
            
            return processor(response); 
        }
    

    这将拦截 msal 异常并在客户端执行重定向以避免任何 CORS 问题。

    它有效,但我们非常欢迎任何建议/更好的做法。

    【讨论】:

      猜你喜欢
      • 2017-04-10
      • 1970-01-01
      • 2010-11-16
      • 2016-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-08
      • 1970-01-01
      相关资源
      最近更新 更多