我无法在 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 问题。
它有效,但我们非常欢迎任何建议/更好的做法。