.net 核心身份 2.1 角色授权不工作

.net core identity 2.1 role authorize not working

我已经在 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 有链接)

但是,用角色装饰控制器总是return未授权

       [Authorize(Roles = "Administrator")]

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

我该如何解决 this/what 是合并源代码的最简单方法,以便我可以 through/debug [Authorize] 标记?

如何修复

However, decorating a controller with a role will always return not authorized

  [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中,unselect Visual Studio
  2. 中的Enable Just My Code
  3. select Enable Source Link Support
  4. Symbols 中,确保 Microsoft Symbol Servers selected

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

调试截图AuthorizeFiler:

我在声明中添加了角色。然后它适用于 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;

在我的 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;
});

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

我也加了

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