.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
- 在
General
中,unselect Visual Studio 中的Enable Just My Code
- select
Enable Source Link Support
- 在
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
我已经在 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
- 在
General
中,unselect Visual Studio 中的 - select
Enable Source Link Support
- 在
Symbols
中,确保 Microsoft Symbol Servers selected
Enable Just My Code
您现在可以调试源代码了。但是,由于过滤器的工作方式,您需要在 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