根据操作名称授权用户

yes*_*ska 22 c# asp.net asp.net-core-mvc asp.net-core

我有很多控制器有很多动作.每个操作都有自己的角色(角色名称= ControllerName.actionName).

在以前的版本中,我可以测试当前用户是否可以使用"通用"AuthorizeAttribute访问操作:

public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
    string currentAction = actionContext.ActionDescriptor.ActionName;
    string currentController = actionContext.ActionDescriptor.ControllerDescriptor.ControllerName;
    Roles = (currentController + "." + currentAction).ToLower();
    base.OnAuthorization(actionContext);
}
Run Code Online (Sandbox Code Playgroud)

使用asp.net 5版本,我发现我需要使用需求(如何在ASP.NET Core中创建自定义AuthorizeAttribute?).问题是AuthorizationContext没有向我们提供有关用户尝试访问的操作的信息.

我不想在每个操作上放置Authorize属性,有没有办法用新框架实现我的要求?(我更喜欢避免使用HttpContext.Current,它不适合管道架构)

jlt*_*rem 47

以下是实施自定义身份验证的一般过程.您的情况可能在第一步中完全解决,因为您可以为装饰您的角色添加声明

1. 通过为用户创建身份进行身份验证

编写中间件并将其插入管道中IApplicationBuilder.UseMiddleware<>是如何进行自定义身份验证的.这是我们提取授权后可能需要的任何信息的地方,并将其放入ClaimsIdentity.我们有一个HttpContext这里,所以我们可以从标题,cookie,请求的路径等获取信息.这是一个例子:

public class MyAuthHandler : AuthenticationHandler<MyAuthOptions>
{
   protected override Task<AuthenticationTicket> HandleAuthenticateAsync()
   {
      // grab stuff from the HttpContext
      string authHeader = Request.Headers["Authorization"] ?? "";
      string path = Request.Path.ToString() ?? "";

      // make a MyAuth identity with claims specifying what we'll validate against
      var identity = new ClaimsIdentity(new[] {
         new Claim(ClaimTypes.Authentication, authHeader),
         new Claim(ClaimTypes.Uri, path)
      }, Options.AuthenticationScheme);

      var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), 
         new AuthenticationProperties(), Options.AuthenticationScheme);
      return Task.FromResult(ticket);
   }
}

public class MyAuthOptions : AuthenticationOptions
{
   public const string Scheme = "MyAuth";
   public MyAuthOptions()
   {
      AuthenticationScheme = Scheme;
      AutomaticAuthentication = true;
   }
}

public class MyAuthMiddleware : AuthenticationMiddleware<MyAuthOptions>
{
   public MyAuthMiddleware(
               RequestDelegate next,
               IDataProtectionProvider dataProtectionProvider,
               ILoggerFactory loggerFactory,
               IUrlEncoder urlEncoder,
               IOptions<MyAuthOptions> options,
               ConfigureOptions<MyAuthOptions> configureOptions)
         : base(next, options, loggerFactory, urlEncoder, configureOptions)
   {
   }

   protected override AuthenticationHandler<MyAuthOptions> CreateHandler()
   {
      return new MyAuthHandler();
   }
}

public static class MyAuthMiddlewareAppBuilderExtensions
{
   public static IApplicationBuilder UseMyAuthAuthentication(this IApplicationBuilder app, string optionsName = "")
   {
      return app.UseMiddleware<MyAuthMiddleware>(
         new ConfigureOptions<MyAuthOptions>(o => new MyAuthOptions()) { Name = optionsName });
   }
}
Run Code Online (Sandbox Code Playgroud)

要使用此中间件Startup.Configure,请在路由之前插入:app.UseMyAuthAuthentication();

2. 通过强制执行身份要求进行授权

我们已经为用户创建了一个身份,但我们仍然需要强制执行它.要做到这一点,我们需要写一个AuthorizationHandler这样的:

  public class MyAuthRequirement : AuthorizationHandler<MyAuthRequirement>, IAuthorizationRequirement
  {
     public override void Handle(AuthorizationContext context, MyAuthRequirement requirement)
     {
        // grab the identity for the MyAuth authentication
        var myAuthIdentities = context.User.Identities
           .Where(x => x.AuthenticationType == MyAuthOptions.Scheme).FirstOrDefault();
        if (myAuthIdentities == null)
        {
           context.Fail();
           return;
        }

        // grab the authentication header and uri types for our identity
        var authHeaderClaim = myAuthIdentities.Claims.Where(x => x.Type == ClaimTypes.Authentication).FirstOrDefault();
        var uriClaim = context.User.Claims.Where(x => x.Type == ClaimTypes.Uri).FirstOrDefault();
        if (uriClaim == null || authHeaderClaim == null)
        {
           context.Fail();
           return;
        }

        // enforce our requirement (evaluate values from the identity/claims)
        if ( /* passes our enforcement test */ )
        {
           context.Succeed(requirement);
        }
        else
        {
           context.Fail();
        }
     }
  }
Run Code Online (Sandbox Code Playgroud)

3.将需求处理程序添加为授权策略

我们的身份验证要求仍然需要添加到Startup.ConfigureServices可以使用它:

// add our policy to the authorization configuration
services.ConfigureAuthorization(auth =>
{
   auth.AddPolicy(MyAuthOptions.Scheme, 
      policy => policy.Requirements.Add(new MyAuthRequirement()));
});
Run Code Online (Sandbox Code Playgroud)

4.使用授权政策

最后一步是通过装饰我们的操作或控制器来强制执行特定操作的此要求[Authorize("MyAuth")].如果我们有许多控制器,每个控制器都有许多需要强制执行的操作,那么我们可能想要创建一个基类并只装饰该单个控制器.

你更简单的情况:

每个操作都有自己的角色(角色名称= ControllerName.actionName>)

如果您已经完成了所有操作,[Authorize(Roles = "controllername.actionname")]那么您可能只需要上面的第1部分.只需添加一个Claim(ClaimTypes.Role, "controllername.actionname")对特定请求有效的新内容即可.

  • 看起来像AuthenticationTicket很老见http://stackoverflow.com/a/37415902/632495 (3认同)