【ASP.NET Core學習】使用JWT認證授權


概述

認證授權是很多系統的基本功能 , 在以前PC的時代 , 通常是基於cookies-session這樣的方式實現認證授權 , 在那個時候通常系統的用戶量都不會很大, 所以這種方式也一直很好運行, 隨着現在都軟件用戶量越來越大, 系統架構也從以前垂直擴展(增加服務器性能) -> 水平擴展(增加服務器數量)

cookies-session 工作方式

客戶端提交用戶信息 -> 服務器識別用戶 -> 服務端保存用戶信息 -> 返回session-id客戶端 -> 客戶端保存session-id -> 每次請求cookies帶上session-id

這種方式也不是不能水平擴展 , 例如 , session復制/第三方保存session(數據庫 , Redis)

名詞解析

  • 認證 : 識別用戶是否合法
  • 授權: 賦予用戶權限 (能訪問哪些資源)
  • 鑒權: 鑒定權限是否合法

Jwt優勢與劣勢

優勢

  1. 無狀態

token 存儲身份驗證所有信息 , 服務端不需要保存用戶身份驗證信息, 減少服務端壓力 , 服務端更容易水平擴展, 由於無狀態, 又會導致它最大缺點 , 很難注銷

  1. 支持跨域訪問

Cookie是不允許垮域訪問的,token支持

  1. 跨語言

基於標准化的 JSON Web Token (JWT) , 不依賴特定某一個語言 , 例如生成對Token可以對多個語言使用(Net , Java , PHP ...)

劣勢

  1. Token有效性問題

后台很難注銷已經發布的Token , 通常需要借助第三方儲存(數據庫/緩存) 實現注銷, 這樣就會失去JWT最大的優勢

  1. 占帶寬

Token長度(取決存放內容) 比session_id大 , 每次請求多消耗帶寬 , token只存必要信息 , 避免token過長

  1. 需要實現續簽

cookies - session 通常是框架已經實現續簽功能, 每次訪問把過期時間更新, JWT需要自己實現, 參考OAuth2刷新Token機制實現刷新Token

  1. 消耗更多CPU

每次請求需要對內容解密和驗證簽名這兩步操作,典型用時間換空間

只能根據自身使用場景決定使用哪一種身份驗證方案 , 沒有一種方案是通用的,完美的

AspNetCore集成Jwt認證

  1. 添加包
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
  1. 添加配置
"JwtOptions": {
    "Issuer": "https://localhost:5001",
    "Audience": "https://localhost:5001",
    "SecurityKey": "1G3l0yYGbOINId3A*ioEi4iyxR7$SPzm"
}
  1. Jwt Bearer 擴展(選項)
public static AuthenticationBuilder AddJwtBearer(this IServiceCollection services, Action<JwtOptions> configureOptions)
{
    if (configureOptions == null) throw new ArgumentNullException(nameof(configureOptions));

    var jwtOptions = new JwtOptions()
    {
        Issuer = "Jwt Authentication",
        Audience = "Wilson Pan Web Api",
    };
    // set customs optoins
    configureOptions(jwtOptions);

    // update Options 
    services.PostConfigure<JwtOptions>(options =>
    {
        options.Issuer = jwtOptions.Issuer;
        options.Audience = jwtOptions.Audience;
        options.SecurityKey = jwtOptions.SecurityKey;
    });

    return services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                    .AddJwtBearer(options =>
                    {
                        options.TokenValidationParameters = new TokenValidationParameters()
                        {
                            ValidIssuer = jwtOptions.Issuer,
                            ValidAudience = jwtOptions.Audience,
                            ValidateIssuer = true,
                            ValidateLifetime = true,
                            ValidateIssuerSigningKey = true,
                            IssuerSigningKey = jwtOptions.SymmetricSecurityKey
                        };
                    });

}
  1. ConfigureServices
services.AddJwtBearer(options =>
{
    options.Issuer = Configuration.GetValue<string>("JwtOptions:Issuer");
    options.Audience = Configuration.GetValue<string>("JwtOptions:Audience");
    options.SecurityKey = Configuration.GetValue<string>("JwtOptions:SecurityKey");
});
  1. Configure
app.UseAuthentication();
app.UseAuthorization();
  1. add AuthorizeController
//define claim 
var claims = new Claim[]
{
    new Claim(ClaimTypes.Name, username),
    new Claim(ClaimTypes.Email, $"{username}@github.com"),
    new Claim(ClaimTypes.Role, username == "WilsonPan" ? "Admin" : "Reader"),
    new Claim(ClaimTypes.Hash, JwtHashHelper.GetHashString($"{username}:{password}:{System.DateTime.Now.Ticks}")),
};

//define JwtSecurityToken
var token = new JwtSecurityToken(
    issuer: _jwtOptions.Issuer,
    audience: _jwtOptions.Audience,
    claims: claims,
    expires: System.DateTime.Now.AddMinutes(5),
    signingCredentials: _jwtOptions.SigningCredentials
);

// generate token
var result = new JwtSecurityTokenHandler().WriteToken(token);
  1. Contrller/Action 添加認證授權
[ApiController]
[Authorize]
[Route("[controller]")]
public class ApiController : ControllerBase
{
    ...
}

[HttpPost]
[Authorize(Roles = "Admin")]
public IActionResult Post()
{
    return Ok();
}

Rest Client

dotnet run
  1. 認證接口
@host = https://localhost:5001

# @name token
POST {{host}}/Authorize  HTTP/1.1
Content-Type: application/x-www-form-urlencoded

#username=Wilson&password=123456
# admin 
username=WilsonPan&password=123456
  1. 需要授權接口
### required authorize
GET  {{host}}/api HTTP/1.1
Authorization: Bearer {{token.response.body.*}}

  1. 需要管理員角色接口
### required authorize
POST {{host}}/api HTTP/1.1
Authorization: Bearer {{token.response.body.*}}


轉發請標明出處:https://www.cnblogs.com/WilsonPan/p/13495936.html
示例代碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM