【发布时间】: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声明,每个角色一次。
标签: c# asp.net-web-api asp.net-core .net-core authorization