1. 程式人生 > 其它 >AspNetCore&JWT認證授權

AspNetCore&JWT認證授權

有時想快速搭建一個簡單應用,並整合登入功能時,總是會被認證授權繞來繞去,一直想著要搞個授權中心,卻把最為簡單快捷的方式拋擲腦後。

認證與授權說來說去還是四個核心步驟,登入退出,登入有效後請求資源,請求人是誰與請求人有沒有許可權請求。

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,望技術有成後能回來看見自己的腳步