我在 Asp.Net Core WebApi 项目中工作并创建了一个角色" admin" 并将其添加到我的用户。但是如果我以管理员身份登录,第一种方法将返回"这是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();
}
在我发送的第二种方法的请求中:
接头: 内容类型:application / JSON 授权:持票人eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJh ......
身体: RoleName =&#34;程序员&#34;
也许我需要在标题中添加一些东西?
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);
}
答案 0 :(得分: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; }
}
答案 1 :(得分:2)
我更改了 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);
}
}