AspNetCore&JWT認證授權
阿新 • • 發佈:2022-04-18
有時想快速搭建一個簡單應用,並整合登入功能時,總是會被認證授權繞來繞去,一直想著要搞個授權中心,卻把最為簡單快捷的方式拋擲腦後。
認證與授權說來說去還是四個核心步驟,登入退出,登入有效後請求資源,請求人是誰與請求人有沒有許可權請求。
JWT
JSON Web Token(JWT)是目前最流行的跨域身份驗證解決方案。其本身只是一種格式或是協議,整合到框架中,然後便按照這種格式或協議來傳遞資訊。
當使用認證授權時,將具有使用者資訊的令牌以JWT格式的呈現,命名為Id token或是Access token。
專案準備
準備一個Asp.Net Core 6.0的WebApi(前端實現不考慮)。按照如上幾個用例挨個實現(退出用例不考慮)
安裝Nuget包
<ItemGroup>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.3" />
<PackageReference Include="IdentityModel" Version="6.0.0" />
</ItemGroup>
生成JWT格式令牌
增加Account控制器
[ApiController]
[Route("[controller]")]
public class AccountController : ControllerBase
{
}
增加JwtOption
該部分資訊使用者Jwt格式中所需要的
public class JwtOptions { public const string Name = "Jwt"; public string Audience { get; set; } public string Issuer { get; set; } public double ExpiresMinutes { get; set; } = 30d; public Encoding Encoding { get; set; } = Encoding.UTF8; public string SymmetricSecurityKeyString { get; set; } public SymmetricSecurityKey SymmetricSecurityKey => new(Encoding.GetBytes(SymmetricSecurityKeyString)); }
服務註冊
builder.Services.Configure<AuthConfigOptions>(builder.Configuration.GetSection(AuthConfigOptions.Name));
配置資訊
appsettings.json中增加該塊配置
{
"Jwt": {
"Audience": "http://localhost:5105",
"Issuer": "http://localhost:5105",
"ExpiresMinutes": 30,
"SymmetricSecurityKeyString": "Symmetric Security Key"
}
}
注入Option
[ApiController]
[Route("[controller]")]
public class AccountController : ControllerBase
{
private readonly JwtOptions _jwtOptions;
public AccountController(IOptionsSnapshot<JwtOptions> jwtOptions)
{
_jwtOptions = jwtOptions.Value;
}
}
增加SignIn方法
此處只模擬存在一個使用者,將該使用者通過Jwt格式儲存資訊並頒發token。
[AllowAnonymous]
[HttpPost("Login")]
public IActionResult SignIn([FromBody] SignInDto dto)
{
//db query...
//return Unauthorized();
//user info
var user = new UserModel()
{
Id = Guid.NewGuid(),
UserName = dto.UserName,
Email = "[email protected]"
};
// 1 定義需要的Cliam資訊
var claims = new[]
{
new Claim(JwtClaimTypes.Id, user.Id.ToString("N")),
new Claim(JwtClaimTypes.Name, user.UserName),
new Claim(JwtClaimTypes.Email, user.Email)
};
// 2 設定SecretKey
var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtOptions.SymmetricSecurityKeyString));
// 3 設定加密演算法
var algorithm = SecurityAlgorithms.HmacSha256;
// 4 生成簽名憑證資訊
var signingCredentials = new SigningCredentials(secretKey, algorithm);
// 5 設定token過期時間
var expires = DateTime.Now.AddMinutes(_jwtOptions.ExpiresMinutes);
// 6 生成token
var securityToken = new JwtSecurityToken(
claims: claims,
issuer: _jwtOptions.Issuer,
audience: _jwtOptions.Audience,
notBefore: DateTime.Now,
expires: expires,
signingCredentials: signingCredentials
);
var jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
var token = jwtSecurityTokenHandler.WriteToken(securityToken);
return Ok(new { token });
}
生成token
請求資源
預設模板生成時自帶了一個WeatherForecast控制器,此處將其作為資源,對其新增Authorize特性,控制資源。
[ApiController]
[Route("[controller]")]
[Authorize]
public class WeatherForecastController : ControllerBase
{
}
因模板中管道部分預設帶上了UseAuthorization,因此再次請求WeatherForecast的方法則會報錯,沒有為Authorization配置相關服務。
增加服務配置
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidIssuer = jwtOptions.Issuer,
ValidateAudience = false,
ValidAudience = jwtOptions.Audience,
ValidateLifetime = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SymmetricSecurityKeyString)),
};
});
增加Authentication中介軟體
app.UseAuthentication();
訪問資源
Authorization中介軟體與Filter區別
在控制器/方法上加Authorize特性,有相應的Filter處理是否有許可權,為什麼存在了一個Authorization中介軟體去提前驗證?
答:Filter的處理屬於MVC的職責範圍,而Authorization則是中介軟體的職責範圍,可以認為是總閘與分閘。
2022-04-17,望技術有成後能回來看見自己的腳步