Asp.Net 基于核心策略的授权以 401 未授权结束

Asp.Net Core policy based authorization ends with 401 Unauthorized

我正在努力建立一个基于自定义策略的授权框架,它将有一组业务规则来授权当前登录的用户。但是,目前骨架总是以 401 Unauthorized.

结尾

这是我的代码,

public class MyAuthorizationRequirement : IAuthorizationRequirement
{
    public MyAuthorizationRequirement()
    {       
    }
}

public class MyAuthorizationHandler : AuthorizationHandler<MyAuthorizationRequirement>
{
    public MyAuthorizationHandler()
    {
    }

    protected override void Handle(AuthorizationContext context, MyAuthorizationRequirement requirement)
    {
        context.Succeed(requirement);
    }
}

然后在 Startup.cs

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IAuthorizationHandler, MyAuthorizationHandler>()
        .AddAuthorization(options =>
        {
            options.AddPolicy("MyAuthorization",
                                policy => policy.Requirements.Add(new MyAuthorizationRequirement()));
        });
    }

这就是我在 HomeController (MVC 6)

中使用它的方式
[Authorize(Policy = "MyAuthorization")]
public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
}

当我不放置 Authorize 属性时,索引视图呈现良好。但是,当我包含 Authorize 属性时,我只收到空白视图。当我检查开发人员工具(网络)时,我得到了以下幕后细节。

Request URL:http://localhost:51129/
Request Method:GET
Status Code:401 Unauthorized
Remote Address:[::1]:51129

调用了我的需求和处理程序 classes 的构造函数的断点,但是 Handler class 的 Handle 方法的断点和 [= Controller class 的 22=] 方法永远不会被调用。

这是因为为每个 [Authorize] 属性添加到管道的 AuthorizeFilter 需要对用户进行身份验证。

如果您查看源代码,您会发现即使没有调用任何策略,它也会确保用户已通过身份验证:

// Note: Default Anonymous User is new ClaimsPrincipal(new ClaimsIdentity())
if (httpContext.User == null ||
    !httpContext.User.Identities.Any(i => i.IsAuthenticated) ||
    !await authService.AuthorizeAsync(httpContext.User, context, Policy))
{
    context.Result = new ChallengeResult(Policy.AuthenticationSchemes.ToArray());
}

条件 httpContext.User.Identities.Any(i => i.IsAuthenticated) 对于匿名用户来说是错误的。

  • AuthorizationOptions 中还有一个 DefaultPolicy 用于验证用户是否已通过身份验证。您可以在 AddAuthorization 配置中将其设置为 null,但即使在这种情况下,上面的 AuthorizeFilter 也会确保用户已通过身份验证

仅供您尝试代码的最简单方法是添加一个 经过身份验证的匿名用户,这样任何匿名用户都会被分配一个经过身份验证的 ClaimsPrincipal(如它有一个 GenericIdentity 而不是一个空的 ClaimsIdentity):

//Add this before app.UseMvc
app.Use(async (context, next) =>
{
    if (!context.User.Identities.Any(i => i.IsAuthenticated))
    {
        //Assign all anonymous users the same generic identity, which is authenticated
        context.User = new ClaimsPrincipal(new GenericIdentity("anonymous"));
    }
    await next.Invoke();

});

在真实的应用程序中,您可能会有一些身份验证框架,用户可以在其中对自己进行身份验证,因此您不会遇到这个问题。

否则您可能需要使用应用程序约定,并将 AuthorizeFilter 替换为您自己的不需要经过身份验证的用户的调整实施, 朝这个方向发展。