Asp.Net Core WebApi:授权属性错误 403
Posted
技术标签:
【中文标题】Asp.Net Core WebApi:授权属性错误 403【英文标题】:Asp.Net Core WebApi: Authorize attribute Error 403 【发布时间】:2018-10-30 19:37:52 【问题描述】:我在 Asp.Net Core WebApi 项目中工作并创建了一个角色 "admin" 并将其添加到我的用户。但是如果我以管理员身份登录,第一种方法会返回“这是管理员!”,但第二种方法会返回错误 403 Forbidden。
如果我从 Authorize 属性中删除 Roles 参数,一切都会好起来的。我不明白为什么我无法访问第二种方法,因为我的用户具有管理员角色。
// Host/api/roles/getroles
[Authorize]
[HttpGet]
public async Task<IEnumerable<string>> GetRoles()
var user = await _userManager.GetUserAsync(User);
bool isAdmin = await _userManager.IsInRoleAsync(user, Roles.AdminRole);
if (isAdmin)
return new[] "This is admin!";
return await _userManager.GetRolesAsync(user);
// ===== Admin Methods =====
// Host/api/roles/createrole
[Authorize(Roles = Roles.AdminRole)]
[HttpPost]
public async Task<IActionResult> CreateRole([FromBody] CreateRoleViewModel model)
if (!ModelState.IsValid)
return BadRequest();
var result = await _roleManager.CreateAsync(new IdentityRole(model.RoleName));
if (!result.Succeeded)
return BadRequest(result);
return Ok();
在我发送的第二种方法的请求中:
标题: 内容类型:应用程序/json 授权:承载eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJh...
正文: RoleName = "程序员"
也许我需要在标题中添加一些内容?
Startup.cs
public class Startup
public IConfiguration Configuration get;
public Startup(IConfiguration configuration)
Configuration = configuration;
public void ConfigureServices(IServiceCollection services)
// ===== Add DbContext ========
var connectionString = Configuration.GetConnectionString("DbConnection");
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
// ===== Add Identity ========
services.AddIdentity<User, IdentityRole> (opts=>
opts.Password.RequiredLength = 5;
opts.Password.RequireNonAlphanumeric = false;
opts.Password.RequireLowercase = false;
opts.Password.RequireUppercase = false;
opts.Password.RequireDigit = false;
)
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
// ===== Add Jwt Authentication ========
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); // => remove default claims
services
.AddAuthentication(options =>
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
;
);
// ===== Add MVC =====
services.AddMvc();
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(
IApplicationBuilder app,
IHostingEnvironment env,
ApplicationDbContext dbContext
)
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
// ===== Use Authentication ======
app.UseAuthentication();
// ===== Use MVC =====
app.UseMvc();
创建 JWT 令牌方法
// ===== Token =====
private async Task<object> GenerateJwtToken(IdentityUser user)
var claims = new List<Claim>
new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(ClaimTypes.NameIdentifier, user.Id)
;
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JwtKey"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var expires = DateTime.Now.AddDays(Convert.ToDouble(_configuration["JwtExpireDays"]));
var token = new JwtSecurityToken(
_configuration["JwtIssuer"],
_configuration["JwtIssuer"],
claims,
expires: expires,
signingCredentials: creds
);
return new JwtSecurityTokenHandler().WriteToken(token);
【问题讨论】:
你在ConfigureServices()
中配置了JWT Bearer Authentication吗?
@DmitryEgorov 是的,我实现了 JWT
@DmitryEgorov 我编辑了问题并添加了 Startup.cs
JWT 传入的 header 中是否包含 roles
声明?
您需要多次添加相同的ClaimTypes.Role
声明,每个角色一次。
【参考方案1】:
我更改了我的 GenerateJwtToken() 方法以将角色添加为声明:
// Get User roles and add them to claims
var roles = await _userManager.GetRolesAsync(user);
AddRolesToClaims(claims, roles);
// ===== Token =====
private async Task<object> GenerateJwtToken(User user)
var claims = new List<Claim>
new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(ClaimTypes.NameIdentifier, user.Id),
;
// Get User roles and add them to claims
var roles = await _userManager.GetRolesAsync(user);
AddRolesToClaims(claims, roles);
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JwtKey"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var expires = DateTime.Now.AddDays(Convert.ToDouble(_configuration["JwtExpireDays"]));
var token = new JwtSecurityToken(
_configuration["JwtIssuer"],
_configuration["JwtIssuer"],
claims,
expires: expires,
signingCredentials: creds
);
return new JwtSecurityTokenHandler().WriteToken(token);
private void AddRolesToClaims(List<Claim> claims, IEnumerable<string> roles)
foreach (var role in roles)
var roleClaim = new Claim(ClaimTypes.Role, role);
claims.Add(roleClaim);
【讨论】:
【参考方案2】:您可以在生成令牌 ex 时在声明中包含您的角色名称:
var claims = new List<Claim>
new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(ClaimTypes.NameIdentifier, user.Id),
new Claim(ClaimTypes.Role,"The Role Of the logged in user, you can get from your DB")
;
或者您可以在传递的参数中使用角色对象,然后添加相同的上述行。
public class IdentityUser : IUser
public IdentityUser();
public IdentityUser(string userName);
public virtual ICollection<IdentityUserClaim> Claims get;
public virtual string Id get; set;
public virtual ICollection<IdentityUserLogin> Logins get;
public virtual string PasswordHash get; set;
public virtual ICollection<IdentityUserRole> Roles get;
public virtual string SecurityStamp get; set;
public virtual string UserName get; set;
【讨论】:
以上是关于Asp.Net Core WebApi:授权属性错误 403的主要内容,如果未能解决你的问题,请参考以下文章
Asp.net Core WebAPI 基于资源的控制器级别之外的授权
如何在 ASP.NET Core 中基于 appsettings 有条件地使用授权
选择 webApi 模板时如何将 ASP.Net 身份添加到 Asp.Net Core?