驗證是確認身分,而授權指的是基於知道你的身分的情況下
根據「策略」(Policy)決定是否有許可權操作資源
策略可以很廣泛,在經過驗證後,會將驗證身分存到ClaimPrincipal
中
因此,可以透過其中的Claim 不同的策略,例如年齡(你已滿18歲,是,Yes),性別55555555555555555555555555,還有最常見的以角色為基礎的授權
我們一樣要用昨天的jwtService來模擬登入取得身分令牌
修改一下,我們再回傳的Identity中加入Role 的 Claim
先說我知道很多寫法沒那麼好,但就是個範例XD
TokenService.cs
public string CreateJwtToken(Member member)
{
var userIdentity = new ClaimsIdentity(new[]
{
new Claim(JwtRegisteredClaimNames.Name, member.Account),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Email, member.Email),
});
userIdentity.AddClaims(member.Roles.Select(role => new Claim(ClaimTypes.Role, role)));
var issuer = "issuer";//_configuration["jwt:Issuer"];
var key = "kewernmkjohiusdfy";//_configuration["jwt:key"];
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
var securityTokenDescriptor = new SecurityTokenDescriptor
{
Issuer = issuer,
Subject = userIdentity,
Expires = DateTime.Now.AddDays(7),
SigningCredentials = signingCredentials
};
var securityToken = _jwtSecurityTokenHandler.CreateToken(securityTokenDescriptor);
var token = _jwtSecurityTokenHandler.WriteToken(securityToken);
return token;
}
在Member 添加Role的屬性,並且在fakeData補上角色
public class Member
{
public string Account { get; set; }
public string Password { get; set; }
public string Email { get; set; }
public string[] Roles { get; set; }
}
private IReadOnlyList<Member> _fakeMembers = new List<Member>()
{
new() { Account = "Admin", Password = "Admin", Email = "admin@gmail.com", Roles = new[] { "Admin", "User" } },
new() { Account = "User", Password = "User", Email = "user@gmail.com", Roles = new []{ "User" } }
};
這邊在TokenController 中加入authorize Service 的驗證TokenController.cs
[HttpGet]
public async Task<string> Get()
{
var authorizeService = HttpContext.RequestServices.GetRequiredService<IAuthorizationService>();
var authorizationResult = await authorizeService.AuthorizeAsync(HttpContext.User, null, new List<IAuthorizationRequirement>()
{
new RolesAuthorizationRequirement(new[] { "Admin" })
});
if(authorizationResult.Succeeded) return "Hello World";
Response.StatusCode = 403;
return "Forbidden";
}
最後需要在pipeline中加入app.UseAuthorization()
的方法
記得放在app.UseAuthentication();
後面
要先有驗證才有授權
透過加入IAuthorizationRequirement
物件,可以添加要針對的授權RolesAuthorizationRequirement
會去驗證當前使用者的Claim
中的 ClaimType.Role
是否有符合的身分
有的話可以順利取到Helloworld 的字眼
沒有的話就會被Forbid
在每個方法都加一個上面的授權應該會崩潰
而且授權的邏輯應該是可共用且與原先方法的邏輯並無這麼的相關
因此,我們可以透過AOP的方式來處理
.NetCore 提供以Policy為基礎的授權方式
可以透過添加Policy加Attribute的方式來做驗證program.cs
builder.Services.AddAuthorization(opt =>
{
var authorizationRequirements = new List<IAuthorizationRequirement>()
{
new RolesAuthorizationRequirement(new[] { "Admin" })
};
var authorizationPolicy = new AuthorizationPolicy(authorizationRequirements, new []{JwtBearerDefaults.AuthenticationScheme});
opt.AddPolicy("Admin", authorizationPolicy);
});
透過Policy的方式在全域添加驗證的政策
再來只要在Controller添加Attrbute即可使用TokenController.cs
[HttpGet]
[Authorize(policy: "Admin", AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public async Task<string> Get()
{
return "Hello World";
}