c# - 根据操作名称授权用户

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

我有许多具有许多操作的 Controller 。每个 Action 都有自己的角色(角色名称 = 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);
}

对于 asp.net 5 版本,我发现我需要使用 requirements ( How do you create a custom AuthorizeAttribute in ASP.NET Core? )。问题是 AuthorizationContext 没有向我们提供有关用户尝试进行的操作的信息。

我不想在每个操作上都添加一个授权属性,有什么方法可以用新框架实现我的要求吗? (我更愿意避免使用 HttpContext.Current,它不太适合管道架构)

最佳答案

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

<强>1。 通过为用户创建身份进行身份验证

编写中间件并通过IApplicationBuilder.UseMiddleware<>将其插入到管道中自定义身份验证是如何完成的。这是我们提取以后授权所需的任何信息的地方,并将其放入 ClaimsIdentity 中。 .我们有一个 HttpContext在这里,我们可以从 header 、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 });
   }
}

要使用此中间件,请将其插入 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();
        }
     }
  }

<强>3。将需求处理程序添加为授权策略

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

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

<强>4。使用授权策略

最后一步是通过用 [Authorize("MyAuth")] 装饰我们的 Action 或 Controller 来强制执行对特定 Action 的要求。 .如果我们有很多 Controller ,每个 Controller 都有很多需要强制执行的操作,那么我们可能想要制作一个基类并只装饰那个 Controller 。

你的情况比较简单:

Each action has it's own Role ( Role name = ControllerName.actionName> )

如果您已经使用 [Authorize(Roles = "controllername.actionname")] 对所有操作进行了微调那么您可能只需要上面的第 1 部分。只需添加一个新的 Claim(ClaimTypes.Role, "controllername.actionname")这对特定请求有效。

关于c# - 根据操作名称授权用户,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31687955/

相关文章:

javascript - 从一个下拉列表中选择值时如何动态生成重复的下拉列表控件

C# Entity Framework 延迟加载(如果未分离)

asp.net - 为什么我要在 MVP 中对业务层进行单元测试

dependency-injection - 是否可以通过约定在.NET Core中注册依赖项?

c# - ASP.NET 核心中间件

c# - 如何将包含十六进制字符的字符串转换为字符串

c# - 静态索引器?

c# - 设置 RadioButtonList 的选定值无法按预期工作

asp.net - 在 asp.net mvc 中显示来自数据库的图像

c# - 为多个 HttpStatusCodes 设置一个 ProducesResponseType typeof