Перенаправление политики ASP.NET Core 3.0 - PullRequest
0 голосов
/ 10 октября 2019

У нас есть эта часть кода, которая контролирует некоторые страницы Premium Service. В методе Deny перенаправляется на страницу обновления для людей, у которых нет премиум-членства.

Код отлично работает в asp.NET core 2, но не работает в asp.NET core 3. context.Resource isбольше не имеет тип AuthorizationFilterContext, но конечная точка не предоставляет члена Result.

¿Как сделать так, чтобы страница перенаправлялась с помощью новой Enpoint, предоставляемой в ядре asp.Net 3?

public Task Deny(AuthorizationHandlerContext context, SubscriptionRequirement requirement)
    {
        var mvcContext = context.Resource as AuthorizationFilterContext;
        if (mvcContext == null)
            return Task.CompletedTask;

        mvcContext.Result = new RedirectToActionResult("Upgrade", "Subscription", new { ReturnUrl = _contextAccessor.HttpContext.Request.Path });
        context.Succeed(requirement);
        return Task.CompletedTask;
    }

1 Ответ

0 голосов
/ 11 октября 2019

Согласно принципу 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 =>{ ... });

Промежуточное программное обеспечение и фильтр ресурсов в основном делают одно и то же: вызывают службу авторизации и перенаправляют при необходимости.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...