Согласно принципу SOC, кажется, что смешивание авторизации с перенаправлением ответа не является хорошей практикой.
Вместо этого вы можете обернуть логику авторизации в политику, а затем вызвать IAuthorizationService и перенаправить в любое место / в любое время.
Допустим, вы определили политику «премиум-членства». И тогда вы можете без каких-либо усилий перенаправить запрос с помощью Middleware / Resource Filter / Action Filter или даже Action Action. Например, я создаю MembershipResourceFilter
, как показано ниже:
public class MembershipResourceFilter : IAsyncResourceFilter
{
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
{
var HttpContext = context.HttpContext;
var authZ = HttpContext.RequestServices.GetRequiredService<IAuthorizationService>();
var routeData= context.RouteData;
var result = await authZ.AuthorizeAsync(HttpContext.User, routeData,"premium membership");
if(!result.Succeeded)
{
context.Result = new RedirectToActionResult("Upgrade", "Subscription", new { ReturnUrl = HttpContext.Request.Path });
}
await next();
}
}
Я тестирую приведенный выше код со следующей политикой, он отлично работает для меня.
services.AddAuthorization(o =>{
o.AddPolicy("premium membership", pb => pb
.RequireAuthenticatedUser()
.RequireAssertion((context)=>{
// check current context.User has premium membership
var user = context.User;
var routeData = context.Resource as RouteData;
if(routeData != null){
try{
var controller = routeData.Values["controller"]?.ToString();
var action = routeData.Values["action"]?.ToString();
// now you get the route value
if(controller == "Home" && action == "Action"){
// ...
return true;
}
}catch{
return false;
}
}
return false;
})
);
});
[Редактировать]
Если вы не хотите изменять [Authorize("Premium")]
, вы можете создать простое промежуточное ПО вместо фильтра ресурсов:
...
app.UseAuthentication();
app.UseRouting();
app.Use(async(ctx,next)=>{
var ep= ctx.Features.Get<IEndpointFeature>()?.Endpoint;
var authAttr = ep?.Metadata?.GetMetadata<AuthorizeAttribute>()
if(authAttr!=null && authAttr.Policy == "premium membership"){
var authService = ctx.RequestServices.GetRequiredService<IAuthorizationService>();
var result = await authService.AuthorizeAsync(ctx.User, ctx.GetRouteData(),authAttr.Policy);
if(!result.Succeeded)
{
var path = $"/Subscription/Upgrade?ReturnUrl={ctx.Request.Path}";
ctx.Response.Redirect(path) ;
return;
}
}
await next();
});
app.UseAuthorization();
app.UseEndpoints(endpoints =>{ ... });
Промежуточное программное обеспечение и фильтр ресурсов в основном делают одно и то же: вызывают службу авторизации и перенаправляют при необходимости.