ASP.NET Core 3.0策略重定向

时间:2019-10-10 09:50:55

标签: c# asp.net-mvc-3 asp.net-core

我们有一部分代码控制着某些Service Premium页面。对于没有高级会员资格的人,方法Deny重定向到升级页面。

该代码在asp.NET core 2上运行完美,但在asp.NET core 3上失败。 context.Resource不再是AuthorizationFilterContext类型,但是Endpoint不提供Result成员。

¿如何使用asp.Net core 3上提供的新Enpoint来使页面重定向?

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;
    }

2 个答案:

答案 0 :(得分:0)

根据SOC原理,似乎将授权与响应重定向混在一起不是一个好习惯。

相反,您可以将授权逻辑包装到策略中,然后调用IAuthorizationService并在需要的任何位置/任何时间重定向。

比方说,您已经定义了“高级会员”政策。然后,您可以毫不费力地使用中间件/资源过滤器/操作过滤器甚至操作方法来重定向请求。例如,我创建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 =>{ ... });

中间件和资源过滤器基本上做同样的事情:调用授权服务并在需要时重定向。

答案 1 :(得分:0)

我通过将struct LoginPage: View { // your login view has the same user data, so user name changes for Home view too @EnvironmentObject var userData: UserData var body: some View { VStack { VLargeCardView(image: "pad22finalsf", category: "Login", heading: "Welcome to PV Pocket!", author: "PAD22") //Google Sign In Button google() .frame(width: 200, height: 50) // I don't know, how you get data, I didn't work with google. so quick code is: .onTapGesture { // when you set userName, in Home view will show MainView at this moment self.userData.userName = "Steve Jobs" } } } } 注入到IHttpContextAccessor构造函数中,然后执行以下操作来解决此问题:

AuthorizationHandler

public Task Deny(AuthorizationHandlerContext context, SubscriptionRequirement requirement) { //your logic here context.Succeed(requirement); return _contextAccessor.HttpContext.ExecuteResultAsync( new RedirectToActionResult("Upgrade", "Subscription", new { ReturnUrl = _contextAccessor.HttpContext.Request.Path })); } HttpContext.ExecuteResultAsync中。

我正在使用core 3.1以防万一。

相关问题