【问题标题】:Create Role-Based Authorization with Windows Authentication使用 Windows 身份验证创建基于角色的授权
【发布时间】:2020-05-23 03:05:46
【问题描述】:

我有一个 ASP.NET Core 应用程序,我想在其中添加基于角色的身份验证。我正在使用 Windows 身份验证,因为它是一个 Intranet 应用程序。我已经有一个自定义数据库,其中包含坦率地说不映射到 IdentityFramework 中的字段的用户/角色。我可以通过 Context.User.Identity.Name 轻松获取登录用户的名称。然后,我想在自定义用户/角色表中查找用户,以便获取该用户的可用角色。然后我想使用在 Controller 或 Action 方法级别装饰的基于注释的身份验证过滤器。例如,[Authorize(roles="admin")]。

我可以通过关闭 Windows 身份验证并使用带有 Cookie 的表单身份验证来完成这项工作。在 AccountController 中,我运行如下代码:

          using(LDAPConnection connection = new LDAPConnection(loginModel.UserName,loginModel.Password))
            {
                List<Claim> claims = new List<Claim> {
                    new Claim(ClaimTypes.Name, loginModel.UserName),
                    new Claim(ClaimTypes.Role, "admin")
                };
                ClaimsIdentity userIdentity = new ClaimsIdentity(claims,"login");
                ClaimsPrincipal principal = new ClaimsPrincipal(userIdentity);
                await HttpContext.SignInAsync(
                    CookieAuthenticationDefaults.AuthenticationScheme,
                    new ClaimsPrincipal(principal),
                    new AuthenticationProperties
                    {
                        IsPersistent = true,
                        ExpiresUtc = DateTime.Now.AddDays(200)
                    });
                return Redirect("/");
            }

然后我会将声明存储在 cookie 中。然后,当我用 [Authorize(roles="admin")] 装饰控制器时,我可以毫无问题地检索视图。授权有效。我想在不登录用户的情况下为 WindowsAuthentication 复制相同的功能。我尝试使用 ClaimsTransformer 并实现基于策略的授权,它有效。但是如果我用 [Authorize(roles="admin")] 装饰它,当我导航到操作方法时它会爆炸。这是 ClaimsTransformer:

public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        var identity = (ClaimsIdentity)principal.Identity;

        List<Claim> claims = new List<Claim> {
            new Claim(ClaimTypes.Name, identity.Name),
            new Claim(ClaimTypes.Role, "admin")
         };
        identity.AddClaims(claims);
        return Task.FromResult(principal);
    }

为了使用 [Authorize(Roles="admin")] 工作,我缺少什么?顺便说一句,我目前正在使用 ASP.NET Core 2.2。

【问题讨论】:

    标签: asp.net-core


    【解决方案1】:

    您可以编写一个自定义策略授权处理程序,您可以在其中获取所有用户的角色并检查它们是否包含您想要的角色名称。

    参考以下步骤:

    1.创建CheckUserRoleRequirement(接受一个参数)

    public class CheckUserRoleRequirement: IAuthorizationRequirement
    {
        public string RoleName { get; private set; }
    
        public CheckUserRoleRequirement(string roleName)
        {
            RoleName = roleName;
        }
    }
    

    2.创建CheckUserRoleHandler

    public class CheckUserRoleHandler : AuthorizationHandler<CheckUserRoleRequirement>
    {
        private readonly IServiceProvider _serviceProvider;
    
        public CheckUserRoleHandler(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                       CheckUserRoleRequirement requirement)
        {
            var name = context.User.Identity.Name;
            using (var scope = _serviceProvider.CreateScope())
            {
                var dbContext = scope.ServiceProvider.GetRequiredService<YourDbContext>();
    
               //your logic to look up the user in the custom user/roles table in order to get the available roles for that user
                List<string> roles = dbContext.UserRoles.Where(...;
                if (roles != null && roles.Contains(requirement.RoleName))
                {
                    context.Succeed(requirement);
                }
            }
            return Task.CompletedTask;
        }
    }
    

    3.在ConfigureServices中注册Handler

    services.AddAuthorization(options =>
    {
        options.AddPolicy("AdminRole", policy =>
            policy.Requirements.Add(new CheckUserRoleRequirement("Admin")));
    });
    
    services.AddSingleton<IAuthorizationHandler, CheckUserRoleHandler>();
    

    4.用法

    [Authorize(Policy = "AdminRole")]
    

    【讨论】:

    • 换个说法,我不需要用 Claims 来愚弄?此外,我想要完成的是不必每次我请求具有授权角色属性的操作方法时都访问数据库或 dbcontext。一旦用户通过身份验证,我想缓存此信息。表单身份验证允许您将其绑定到具有过期时间的 cookie。
    【解决方案2】:

    我知道这个答案有点晚了,但我今天一直在解决同样的问题,我在类似帖子中看到的答案都没有解决我的问题。

    以下是我为能够在我的控制器上通过 Windows 身份验证使用 [Authorize(Roles = "Admin")] 所采取的步骤。

    1. 在 Startup.cs 的 Configure() 方法中仔细检查 UseAuthentication() 是否位于 UseAuthorization() 之前
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                else
                {
                    app.UseExceptionHandler("/Home/Error");
                    app.UseHsts();
                }
                app.UseStaticFiles();
                app.UseRouting();
                app.UseAuthentication(); // <--- this needs to be before
                app.UseAuthorization(); // <----this
    
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapControllerRoute(
                        name: "default",
                        pattern: "{controller=Hccc}/{action=Index}/");
                });
            }
    
    1. 有一个声明转换器来处理必要的角色。例如,
            public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
            {
                var ci = (ClaimsIdentity)principal.Identity;
                var user = UserAuth.GetUserRole(ci.Name); // gets my user from db with role
                // handle your roles however you need.
                foreach(var role in user.Roles)
                {
                    var roleClaim = new Claim(ci.RoleClaimType, role.RoleName);
                    ci.AddClaim(roleClaim);
                }
    
                return Task.FromResult(principal);
            }
    
    1. 在 Startup.cs 中设置 ConfigureServices() 方法来处理授权
            services.AddSingleton<IClaimsTransformation, ClaimsTransformer>();
            // Implement a policy called "AdminOnly" that uses "Windows" authentication
            // The policy requires Role "Admin"
            services.AddAuthorization(options =>
            {
                options.AddPolicy("AdminOnly", policy =>
                {
                    policy.AddAuthenticationSchemes("Windows");
                    policy.RequireRole("Admin");
                });
            });
            services.AddMvc();
            services.AddControllersWithViews();
    
    1. 使用[Authorize] 标签来实施策略。就我而言,我想阻止对控制器的访问,除非用户是“管理员”。
            [Authorize(Policy = "AdminOnly")]
            public class UsersController : Controller
            {
    
            }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-05-17
      • 2021-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-20
      • 2012-02-20
      相关资源
      最近更新 更多