使用 ASP.NET Core 3.1 Identity with MongoDB 授权不为角色工作
Authorize not working for roles using ASP.NET Core 3.1 Identity with MongoDB
更新:不仅仅是管理员角色不起作用 - 似乎任何需要授权的路由都返回 401。
我想创建一个管理员角色来控制对我的 AdminController 的访问。我的堆栈是 MongoDb/.NET Core(3.1),用于 API/ Angular 9 前端。
我用角色
为我的数据库播种
private static void SeedRoles(RoleManager<MongoRole> roleManager)
{
if (!roleManager.RoleExistsAsync("User").Result)
{
MongoRole role = new MongoRole();
role.Name = "User";
IdentityResult roleResult = roleManager.
CreateAsync(role).Result;
}
if (!roleManager.RoleExistsAsync("Admin").Result)
{
MongoRole role = new MongoRole();
role.Name = "Admin";
IdentityResult roleResult = roleManager.
CreateAsync(role).Result;
}
}
在另一种种子方法中,我已将以下 2 个角色添加到我的用户帐户
userManager.AddToRoleAsync(user, "User").Wait();
userManager.AddToRoleAsync(user, "Admin").Wait();
在我的启动文件中,我配置了我的 mongo 身份提供商
services.AddIdentityMongoDbProvider<AspNetCore.Identity.Mongo.Model.MongoUser, AspNetCore.Identity.Mongo.Model.MongoRole>(identityOptions =>
{
identityOptions.Password.RequiredLength = 6;
identityOptions.Password.RequireLowercase = false;
identityOptions.Password.RequireUppercase = false;
identityOptions.Password.RequireNonAlphanumeric = false;
identityOptions.Password.RequireDigit = false;
}, mongoIdentityOptions => {
mongoIdentityOptions.ConnectionString = **REMOVED CONN STR FROM HERE**;
});
我在用户控制器中的登录方法从我的用户那里获取角色并将它们添加到声明列表中——据我所知,这是为了将其包含在可以检查角色的令牌中。当我调试并在此方法上添加断点时,很明显角色正在添加到 claimList - 所以我不确定问题是否存在。
// POST api/user/login
[HttpPost]
[AllowAnonymous]
public async Task<ActionResult> Login([FromBody]LoginEntity model)
{
if (ModelState.IsValid)
{
var result = await _signInManager.PasswordSignInAsync(model.UserName, model.Password, false, false);
if (result.Succeeded)
{
string key = model.UserName + "ezgig321";
var appUser = _userManager.Users.SingleOrDefault(r => r.UserName == model.UserName);
var issuer = "ezgig";
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var roles = await _userManager.GetRolesAsync(appUser);
var claimList = new List<Claim>();
foreach (var role in roles)
{
var roleClaim = new Claim(ClaimTypes.Role, role);
claimList.Add(roleClaim);
}
claimList.Add(new Claim("username", model.UserName));
//var token = AuthenticationHelper.GenerateJwtToken(model.Email, appUser, _configuration);
var token = new JwtSecurityToken(issuer, //Issure
issuer, //Audience
claimList,
expires: DateTime.Now.AddDays(1),
signingCredentials: credentials);
var encodedJwt = new JwtSecurityTokenHandler().WriteToken(token);
var rootData = new LoginResponse(encodedJwt, appUser.UserName);
return Ok(rootData);
}
return StatusCode((int)HttpStatusCode.Unauthorized, "Bad Credentials");
}
string errorMessage = string.Join(", ", ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage));
return BadRequest(errorMessage ?? "Bad Request");
}
然而,当我使用以管理员角色登录到我的帐户时返回的 JWT - 当我尝试访问我放入管理控制器的此测试方法时,我仍然收到 401 未经授权。
[Authorize(Roles ="Admin")]
[Route("api/[controller]/[action]")]
public class AdminController : Controller
{
// GET api/admin/admintest
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[HttpGet]
public ActionResult AdminTest()
{
return Ok("you seem to have admin authorisation");
}
原来是愚蠢导致了这个错误。我在 Register/Login 端点的发行者和 JWT 关键变量中进行了硬编码,但我写错了。
因为它们与 startup.cs 文件中的 issuer/jwt 键不匹配(见下文)...
services.AddAuthentication(options =>
{
//Set default Authentication Schema as Bearer
options.DefaultAuthenticateScheme =
JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme =
JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme =
JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(cfg =>
{
cfg.RequireHttpsMetadata = false;
cfg.SaveToken = true;
cfg.TokenValidationParameters =
new TokenValidationParameters
{
ValidIssuer = Configuration["JwtIssuer"],
ValidAudience = Configuration["JwtIssuer"],
IssuerSigningKey =
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JwtKey"])),
ClockSkew = TimeSpan.Zero // remove delay of token when expire
};
});
这意味着 JWT 密钥因无效而被拒绝。对不起,如果有人在这上面浪费了时间。
更新:不仅仅是管理员角色不起作用 - 似乎任何需要授权的路由都返回 401。
我想创建一个管理员角色来控制对我的 AdminController 的访问。我的堆栈是 MongoDb/.NET Core(3.1),用于 API/ Angular 9 前端。
我用角色
为我的数据库播种 private static void SeedRoles(RoleManager<MongoRole> roleManager)
{
if (!roleManager.RoleExistsAsync("User").Result)
{
MongoRole role = new MongoRole();
role.Name = "User";
IdentityResult roleResult = roleManager.
CreateAsync(role).Result;
}
if (!roleManager.RoleExistsAsync("Admin").Result)
{
MongoRole role = new MongoRole();
role.Name = "Admin";
IdentityResult roleResult = roleManager.
CreateAsync(role).Result;
}
}
在另一种种子方法中,我已将以下 2 个角色添加到我的用户帐户
userManager.AddToRoleAsync(user, "User").Wait();
userManager.AddToRoleAsync(user, "Admin").Wait();
在我的启动文件中,我配置了我的 mongo 身份提供商
services.AddIdentityMongoDbProvider<AspNetCore.Identity.Mongo.Model.MongoUser, AspNetCore.Identity.Mongo.Model.MongoRole>(identityOptions =>
{
identityOptions.Password.RequiredLength = 6;
identityOptions.Password.RequireLowercase = false;
identityOptions.Password.RequireUppercase = false;
identityOptions.Password.RequireNonAlphanumeric = false;
identityOptions.Password.RequireDigit = false;
}, mongoIdentityOptions => {
mongoIdentityOptions.ConnectionString = **REMOVED CONN STR FROM HERE**;
});
我在用户控制器中的登录方法从我的用户那里获取角色并将它们添加到声明列表中——据我所知,这是为了将其包含在可以检查角色的令牌中。当我调试并在此方法上添加断点时,很明显角色正在添加到 claimList - 所以我不确定问题是否存在。
// POST api/user/login
[HttpPost]
[AllowAnonymous]
public async Task<ActionResult> Login([FromBody]LoginEntity model)
{
if (ModelState.IsValid)
{
var result = await _signInManager.PasswordSignInAsync(model.UserName, model.Password, false, false);
if (result.Succeeded)
{
string key = model.UserName + "ezgig321";
var appUser = _userManager.Users.SingleOrDefault(r => r.UserName == model.UserName);
var issuer = "ezgig";
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var roles = await _userManager.GetRolesAsync(appUser);
var claimList = new List<Claim>();
foreach (var role in roles)
{
var roleClaim = new Claim(ClaimTypes.Role, role);
claimList.Add(roleClaim);
}
claimList.Add(new Claim("username", model.UserName));
//var token = AuthenticationHelper.GenerateJwtToken(model.Email, appUser, _configuration);
var token = new JwtSecurityToken(issuer, //Issure
issuer, //Audience
claimList,
expires: DateTime.Now.AddDays(1),
signingCredentials: credentials);
var encodedJwt = new JwtSecurityTokenHandler().WriteToken(token);
var rootData = new LoginResponse(encodedJwt, appUser.UserName);
return Ok(rootData);
}
return StatusCode((int)HttpStatusCode.Unauthorized, "Bad Credentials");
}
string errorMessage = string.Join(", ", ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage));
return BadRequest(errorMessage ?? "Bad Request");
}
然而,当我使用以管理员角色登录到我的帐户时返回的 JWT - 当我尝试访问我放入管理控制器的此测试方法时,我仍然收到 401 未经授权。
[Authorize(Roles ="Admin")]
[Route("api/[controller]/[action]")]
public class AdminController : Controller
{
// GET api/admin/admintest
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[HttpGet]
public ActionResult AdminTest()
{
return Ok("you seem to have admin authorisation");
}
原来是愚蠢导致了这个错误。我在 Register/Login 端点的发行者和 JWT 关键变量中进行了硬编码,但我写错了。
因为它们与 startup.cs 文件中的 issuer/jwt 键不匹配(见下文)...
services.AddAuthentication(options =>
{
//Set default Authentication Schema as Bearer
options.DefaultAuthenticateScheme =
JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme =
JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme =
JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(cfg =>
{
cfg.RequireHttpsMetadata = false;
cfg.SaveToken = true;
cfg.TokenValidationParameters =
new TokenValidationParameters
{
ValidIssuer = Configuration["JwtIssuer"],
ValidAudience = Configuration["JwtIssuer"],
IssuerSigningKey =
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JwtKey"])),
ClockSkew = TimeSpan.Zero // remove delay of token when expire
};
});
这意味着 JWT 密钥因无效而被拒绝。对不起,如果有人在这上面浪费了时间。