【问题标题】:.net core identity 2.1 role authorize not working.net 核心身份 2.1 角色授权不起作用
【发布时间】:2019-03-02 17:32:36
【问题描述】:

在 2.1 之前,我已经多次实施基于角色的身份验证。按照步骤搭建新的 2.1 标识。

我扩展了 IdentityUser 模型以添加其他字段,登录工作正常,新字段出现。

startup.cs 配置服务包含

         services.AddDefaultIdentity<AppUser>()
            .AddRoles<IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>();

我为角色播种

         IdentityRole role = new IdentityRole();
         role.Name = "Administrator";
         IdentityResult roleResult = roleManager.
         CreateAsync(role).Result;

然后创建一个用户并添加到角色中

        AppUser user = new AppUser();
        user.UserName = "Admin";
        user.Email = "admin@admin.com";
        user.Name = "Administrator";
        user.LockoutEnabled = false;
        user.EmailConfirmed = true;

        IdentityResult result = userManager.CreateAsync(user, "password").Result;

        if (result.Succeeded)
        {
            userManager.AddToRoleAsync(user, "Administrator").Wait();
        }

一切顺利,数据库看起来很好(AspNetUserRoles 有链接)

但是,用角色装饰控制器总是会返回未授权

       [Authorize(Roles = "Administrator")]

但是,使用[Authorize](无角色)进行简单的登录检查即可。

我该如何解决这个问题/合并源代码的最简单方法是什么,以便我可以单步调试/调试[Authorize] 标签?

【问题讨论】:

  • 要调试也许你可以使用 [Authorize] 并在操作方法中添加某处: var claim = User.Claims;因此,您可以查看声明是否真的存在
  • 您是否配置了cookies?

标签: asp.net-core asp.net-core-mvc asp.net-core-identity


【解决方案1】:

如何解决

但是,用角色装饰控制器总是会返回未授权

  [Authorize(Roles = "Administrator")]

这是 2.1 版本中的一个已知错误。请在此处查看issue。

我听从了of using the old api suggested by HaoK and C-BERBER 的建议,现在它可以完美运行了。

这是我的DbContext:

public class ApplicationDbContext : IdentityDbContext<AppUser,IdentityRole,string>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }
}

使用旧式 api 配置身份:

services.AddIdentity<AppUser, IdentityRole>()
        .AddRoleManager<RoleManager<IdentityRole>>()
        .AddDefaultUI()
        .AddDefaultTokenProviders()
        .AddEntityFrameworkStores<ApplicationDbContext>();

最后,注销并重新登录,现在可以正常工作了。

如何调试源代码

我猜你不想调试 AuthorizeAttribe 本身,因为它是在编译时处理的。如果您要调试AuthorizeFilter,可以按照以下步骤进行:

点击Tools -> Options -> Debugging

  1. 在General 内,取消选择 Visual Studio 中的Enable Just My Code
  2. 选择Enable Source Link Support
  3. 在 Symbols 中,确保选择了 Microsoft Symbol Servers

你现在可以调试源代码了。但是,由于过滤器的工作方式,您需要在 MVC 之前设置一个断点。我只是设置了一个虚拟中间件,它将在 MVC 路由器处理程序之前发生:

调试AuthorizeFiler的截图:

【讨论】:

    【解决方案2】:

    在我的 ASP.NET Core 3(预览版)+ Angular 的情况下,解决方案在 AddAuthentication

    services.AddDefaultIdentity<ApplicationUser>()
        .AddRoles<IdentityRole>()
        .AddRoleManager<RoleManager<IdentityRole>>()
        .AddEntityFrameworkStores<ApplicationDbContext>();
    
    services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
        options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
        options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
    });
    

    【讨论】:

      【解决方案3】:

      我在声明中添加了角色。然后它适用于 UI (HttpContext.User.IsInRole("Admin")) 和 authorize 属性 ([Authorize(Roles = "Admin")])。

      Startup.cs 文件:

      public void ConfigureServices(IServiceCollection services)
      {    
          services.AddIdentity<ApplicationUser, IdentityRole>()                
            .AddEntityFrameworkStores<WandContext>();
          ///..... other code
      } 
      

      在身份验证期间,我将角色添加到我的声明中。

      var invalidLoginAttempt = false;
      var user = await _userManager.FindByNameAsync(loginModel.Email);
      if (user != null)
      {
          var result = await _signInManager.CheckPasswordSignInAsync(user, loginModel.Password, lockoutOnFailure: true);
      
          if (result.Succeeded)
          {                                       
              var customClaims = new List<Claim>
              {
                  new Claim(ClaimTypes.Role, Role.Admin)
              };
      
              var claimsIdentity = new ClaimsIdentity(customClaims, CookieAuthenticationDefaults.AuthenticationScheme);
              var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
      
              await _signInManager.Context.SignInAsync(IdentityConstants.ApplicationScheme,
                  claimsPrincipal, new AuthenticationProperties { IsPersistent = loginModel.RememberMe });
      
              return LocalRedirect(returnUrl);
          }
          else if (result.IsLockedOut)
              ModelState.AddModelError(string.Empty, "This account has been locked out, please try again later.");
          else
              invalidLoginAttempt = true;
      }
      else
          invalidLoginAttempt = true;
      

      【讨论】:

        【解决方案4】:

        我通过在Startup.cs 中调用JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); 之前调用services.AddAuthentication 来获得角色工作。

        我也加了

        services.AddScoped<IProfileService, ProfileService>();
        

        和ProfileService.cs 看起来像这样将角色映射到声明:

        public sealed class ProfileService : IProfileService
        {
            private readonly IUserClaimsPrincipalFactory<ApplicationUser> _userClaimsPrincipalFactory;
            private readonly UserManager<ApplicationUser> _userMgr;
            private readonly RoleManager<IdentityRole> _roleMgr;
        
            public ProfileService(
                UserManager<ApplicationUser> userMgr,
                RoleManager<IdentityRole> roleMgr,
                IUserClaimsPrincipalFactory<ApplicationUser> userClaimsPrincipalFactory)
            {
                _userMgr = userMgr;
                _roleMgr = roleMgr;
                _userClaimsPrincipalFactory = userClaimsPrincipalFactory;
            }
        
            public async Task GetProfileDataAsync(ProfileDataRequestContext context)
            {
                string sub = context.Subject.GetSubjectId();
                ApplicationUser user = await _userMgr.FindByIdAsync(sub);
                ClaimsPrincipal userClaims = await _userClaimsPrincipalFactory.CreateAsync(user);
        
                List<Claim> claims = userClaims.Claims.ToList();
                claims = claims.Where(claim => context.RequestedClaimTypes.Contains(claim.Type)).ToList();
        
                if (_userMgr.SupportsUserRole)
                {
                    IList<string> roles = await _userMgr.GetRolesAsync(user);
                    foreach (var roleName in roles)
                    {
                        claims.Add(new Claim(JwtClaimTypes.Role, roleName));
                        if (_roleMgr.SupportsRoleClaims)
                        {
                            IdentityRole role = await _roleMgr.FindByNameAsync(roleName);
                            if (role != null)
                            {
                                claims.AddRange(await _roleMgr.GetClaimsAsync(role));
                            }
                        }
                    }
                }
        
                context.IssuedClaims = claims;
            }
        
            public async Task IsActiveAsync(IsActiveContext context)
            {
                string sub = context.Subject.GetSubjectId();
                ApplicationUser user = await _userMgr.FindByIdAsync(sub);
                context.IsActive = user != null;
            }
        }
        

        来源:

        https://ffimnsr.medium.com/adding-identity-roles-to-identity-server-4-in-net-core-3-1-d42b64ff6675

        【讨论】:

          猜你喜欢
          • 2015-10-08
          • 2018-12-05
          • 1970-01-01
          • 2021-11-09
          • 1970-01-01
          • 2017-10-28
          • 2020-09-23
          • 2020-07-27
          • 1970-01-01
          相关资源
          最近更新 更多