Abp授权失败重定向至登录页,修改为返回401
Issues/2643所说:当您调用需要身份验证的控制器时,身份验证中间件会发现当前用户未通过身份验证,并调用 ChallengeAsync(DefaultChallengeScheme 是标识 Cookie)。此时,请求已被短路。
如果匿名控制器调用应用程序服务方法,它将执行 ABP 筛选器和侦听器。框架抛出 AbpAuthorizationException,过滤器将异常包装到 401 中,依此类推。
在Abp5.X版本中,Abp官方将认证行为保持一致(Issues/9926),从而导致了之后版本,匿名访问需认证API将会重定向至登录页。这是一次非常好的改动。
第一种是.Net Core
传统解决方案。
private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
{
context.Services.ConfigureApplicationCookie(options =>
{
options.ForwardDefaultSelector = ctx =>
{
return ctx.Request.Path.StartsWithSegments("/api") ? JwtBearerDefaults.AuthenticationScheme : null;
};
});
context.Services.AddAuthentication().AddJwtBearer(options =>
{
options.Authority = configuration["AuthServer:Authority"];
options.RequireHttpsMetadata = Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]);
options.Audience = "Test";
options.BackchannelHttpHandler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
};
options.Events = new JwtBearerEvents
{
OnChallenge = async context =>
{
context.HandleResponse();
context.Response.ContentType = "application/json;charset=utf-8";
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
var response = new RemoteServiceErrorResponse(new RemoteServiceErrorInfo("未认证"));
await context.Response.WriteAsJsonAsync(response);
},
OnForbidden = async context =>
{
context.Response.ContentType = "application/json;charset=utf-8";
context.Response.StatusCode = StatusCodes.Status403Forbidden;
var response = new RemoteServiceErrorResponse(new RemoteServiceErrorInfo("未授权"));
await context.Response.WriteAsJsonAsync(response);
}
};
});
}
其中返回信息根据实际情况填写。
第二种方法是将行为尽量和Abp趋于一致。仅限**.NET 5.0/6.0**
.
新建AuthorizationExceptionHandler
类,继承IAbpAuthorizationExceptionHandler
接口。
public class AuthorizationExceptionHandler : IAbpAuthorizationExceptionHandler
{
private readonly Func
新建AuthorizationMiddlewareResultHandler
类,继承IAuthorizationMiddlewareResultHandler
接口。
public class AuthorizationMiddlewareResultHandler : IAuthorizationMiddlewareResultHandler
{
private readonly IAbpAuthorizationExceptionHandler _authorizationExceptionHandler;
public AuthorizationMiddlewareResultHandler(IAbpAuthorizationExceptionHandler authorizationExceptionHandler)
{
_authorizationExceptionHandler = authorizationExceptionHandler;
}
public async Task HandleAsync(
RequestDelegate next,
HttpContext context,
AuthorizationPolicy policy,
PolicyAuthorizationResult authorizeResult)
{
if (authorizeResult.Challenged)
{
await context.ChallengeAsync();
await _authorizationExceptionHandler.HandleAsync(
new AbpAuthorizationException(code: AbpAuthorizationErrorCodes.GivenPolicyHasNotGranted), context);
return;
}
if (authorizeResult.Forbidden)
{
await context.ForbidAsync();
await _authorizationExceptionHandler.HandleAsync(
new AbpAuthorizationException(code: AbpAuthorizationErrorCodes.GivenPolicyHasNotGranted), context);
return;
}
await next(context);
}
}
将其注入到容器内。
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddSingleton();
context.Services.Replace(ServiceDescriptor.Singleton());
}
别忘记将任何以**/api**
开头的请求转发到 JWT 方案。
private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
{
context.Services.ConfigureApplicationCookie(options =>
{
options.ForwardDefaultSelector = ctx =>
{
return ctx.Request.Path.StartsWithSegments("/api") ? JwtBearerDefaults.AuthenticationScheme : null;
};
});
...
}