[轉]C# 實現Jwt bearer Authentication


本文轉自:https://www.cnblogs.com/aishangyipiyema/p/9262642.html

什么是JWT

JWT(JSON Web Token), 顧名思義就是在Web上以JSON格式傳輸的Token(RFC 7519)。

該Token被設計為緊湊聲明表示格式,特別適用於分布式站點的單點登錄(SSO)場景。

緊湊 :意味着size小,所以可以在URL中,Header中,Post Parameter中進行傳輸,並且包含了所需要的信息。

JWT的構成

JWT一般由三段構成,用"."號分隔開

Header.Payload.Signature

例如:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

點擊鏈接 如下圖

圖左邊為Header.Payload.Signature的base64編碼

圖右構成

Header

  • alg:聲明加密的算法 ,這里為HS256
  • typ:聲明類型,這里為JWT

然后將Header進行base64編碼 得到第一部分

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

Payload

由三部分構成

  • 標准中注冊的聲明

  • 公共的聲明

  • 私有的聲明

    標准中注冊的聲明 (建議但不強制使用) :

    • iss: jwt簽發者

    • sub: jwt所面向的用戶

    • aud: 接收jwt的一方

    • exp: jwt的過期時間,這個過期時間必須要大於簽發時間

    • nbf: 定義在什么時間之前,該jwt都是不可用的.

    • iat: jwt的簽發時間

    • jti: jwt的唯一身份標識,主要用來作為一次性token,從而回避重放攻擊。

    公共的聲明 :

公共的聲明可以添加任何的信息,一般添加用戶的相關信息或其他業務需要的必要信息.但不建議添加敏感信息,因為該部分在客戶端可解密.

私有的聲明 :

私有聲明是提供者和消費者所共同定義的聲明,一般不建議存放敏感信息,因為base6編碼可以歸類為明文信息 。

定義一個payload:

{
  "sub": "1234567890", "name": "John Doe", "admin": true } 

然后將其進行base64加密,得到Jwt的第二部分。

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ

Signature(數字簽名,防止信息被篡改)

jwt的第三部分是一個簽證信息,這個簽證信息由三部分組成:

  • Header (base64后的)

  • Payload (base64后的)

  • Secret

    這個部分需要base64加密后的header和base64加密后的payload使用.連接組成的字符串,然后通過header中聲明的加密方式進行加鹽secret組合加密,然后就構成了jwt的第三部分 。

    // javascript var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload); var signature = HMACSHA256(encodedString, 'secret');

    將這三部分用.連接成一個完整的字符串,構成了最終的jwt:

    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

    注意:secret是保存在服務器端的,jwt的簽發生成也是在服務器端的,secret就是用來進行jwt的簽發和jwt的驗證,所以,它就是你服務端的私鑰,在任何場景都不應該流露出去。一旦客戶端得知這個secret, 那就意味着客戶端是可以自我簽發jwt了。

下面我們自己來實現一下 JwtBearer Authentication

  1. 新建一個WebApi項目

  1. 新建JwtSeetings類

        public class JwtSeetings { /// <summary> /// 誰頒發的jwt /// </summary> public string Issuer { get; set; } /// <summary> /// 誰使用這個jwt /// </summary> public string Audience { get; set; } /// <summary> /// secret是保存在服務器端的,jwt的簽發生成也是在服務器端的,secret就是用來進行jwt的簽發和jwt的驗證, /// 所以,它就是你服務端的私鑰,在任何場景都不應該流露出去。一旦客戶端得知這個secret, 那就意味着客戶端是可以自我簽發jwt了 /// 通過jwt header中聲明的加密方式進行加鹽secret組合加密,然后就構成了jwt的第三部分 /// </summary> public string SecretKey { get; set; } }
  2. appsettings.json里面配置如下

    "JwtSeetings": { "Issuer": "http://localhost:5000", "Audience": "http://localhost:5000", "SecretKey": "zhoudafu201807041123"
  3. Startup類里面ConfigureServices添加如下代碼

        services.Configure<JwtSeetings>(Configuration.GetSection("JwtSeetings")); var jwtSeetings = new JwtSeetings(); //綁定jwtSeetings Configuration.Bind("JwtSeetings", jwtSeetings); services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidIssuer = jwtSeetings.Issuer, ValidAudience = jwtSeetings.Audience, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSeetings.SecretKey)) }; }) ;
  4. Startup類里面Configure添加如下代碼

     app.UseAuthentication();
  5. 新增AuthroizeController控制器,並添加如下代碼

    [HttpPost] public ActionResult Post([FromBody]LoginViewModel loginViewModel) { if (!ModelState.IsValid) { return BadRequest(); } if (loginViewModel.Name == "jack" && loginViewModel.Password == "rose") { var claims = new Claim[] { new Claim(ClaimTypes.Name,"jack"), new Claim(ClaimTypes.Role,"admin") }; var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSeetings.SecretKey)); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken( _jwtSeetings.Issuer, _jwtSeetings.Audience, claims, DateTime.Now, DateTime.Now.AddMinutes(30), creds ); return Ok(new { token = new JwtSecurityTokenHandler().WriteToken(token) }); } return BadRequest(); }
  6. 給ValuesController控制器打上[Authorize]特性

  7. 用Postman直接訪問http://localhost:5000/api/Values 返回401

    1530672358385

  8. 用Postman訪問http://localhost:5000/api/Authroize 得到Token

    1530672442132

  9. 通過Bearer訪問成功

1530672572449

源代碼 https://github.com/HisKingdom/JwtAuthSample

參考博客:https://www.jianshu.com/p/576dbf44b2ae

 


免責聲明!

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



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