JSON Web Token(JWT)是目前最流行的跨域身份驗證解決方案。
JWT的官網地址:https://jwt.io/
通俗地來講,JWT是能代表用戶身份的令牌,可以使" />

asp.net core集成JWT的步驟記錄

 更新時間:2019-06-25 03:01:05   作者:佚名   我要評論(0)

【什么是JWT】
JSON Web Token(JWT)是目前最流行的跨域身份驗證解決方案。
JWT的官網地址:https://jwt.io/
通俗地來講,JWT是能代表用戶身份的令牌,可以使

【什么是JWT】

JSON Web Token(JWT)是目前最流行的跨域身份驗證解決方案。

JWT的官網地址:https://jwt.io/

通俗地來講,JWT是能代表用戶身份的令牌,可以使用JWT令牌在api接口中校驗用戶的身份以確認用戶是否有訪問api的權限。

JWT中包含了身份認證必須的參數以及用戶自定義的參數,JWT可以使用秘密(使用HMAC算法)或使用RSA或ECDSA的公鑰/私鑰對進行簽名。

【什么時候應該使用JSON Web令牌?】

授權:這是使用JWT的最常見方案。一旦用戶登錄,每個后續請求將包括JWT,允許用戶訪問該令牌允許的路由,服務和資源。Single Sign On是一種現在廣泛使用JWT的功能,因為它的開銷很小,并且能夠在不同的域中輕松使用。

信息交換:JSON Web令牌是在各方之間安全傳輸信息的好方法。因為JWT可以簽名 - 例如,使用公鑰/私鑰對 - 您可以確定發件人是他們所說的人。此外,由于使用標頭和有效負載計算簽名,您還可以驗證內容是否未被篡改。

【JWT有什么優勢?】  

  1. 用戶向服務器發送用戶名和密碼。
  2. 服務器驗證通過后,在當前對話(session)里面保存相關數據,比如用戶角色、登錄時間等等。
  3. 服務器向用戶返回一個 session_id,寫入用戶的 Cookie。
  4. 用戶隨后的每一次請求,都會通過 Cookie,將 session_id 傳回服務器。
  5. 服務器收到 session_id,找到前期保存的數據,由此得知用戶的身份。

  這種模式的問題在于,擴展性(scaling)不好。單機當然沒有問題,如果是服務器集群,或者是跨域的服務導向架構,就要求 session 數據共享,每臺服務器都能夠讀取 session。如果session存儲的節點掛了,那么整個服務都會癱瘓,體驗相當不好,風險也很高。

  相比之下,JWT的實現方式是將用戶信息存儲在客戶端,服務端不進行保存。每次請求都把令牌帶上以校驗用戶登錄狀態,這樣服務就變成了無狀態的,服務器集群也很好擴展。

【JWT令牌結構】

在緊湊的形式中,JSON Web Tokens由dot(.)分隔的三個部分組成,它們是:

  • Header 頭
  • Payload 有效載荷
  • Signature 簽名

因此,JWT通常如下所示:

  xxxxx.yyyyy.zzzzz

1.Header 頭

標頭通常由兩部分組成:令牌的類型,即JWT,以及正在使用的簽名算法,例如HMAC SHA256或RSA。

例如:

{
 "alg": "HS256",
 "typ": "JWT"
}

然后,這個JSON被編碼為Base64Url,形成JWT的第一部分。

2.Payload有效載荷

Payload 部分也是一個 JSON 對象,用來存放實際需要傳遞的數據。JWT 規定了7個官方字段,供選用。

  • iss (issuer):簽發人
  • exp (expiration time):過期時間
  • sub (subject):主題
  • aud (audience):受眾
  • nbf (Not Before):生效時間
  • iat (Issued At):簽發時間
  • jti (JWT ID):編號

除了官方字段,你還可以在這個部分定義私有字段,下面就是一個例子。例如:

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

注意,JWT 默認是不加密的,任何人都可以讀到,所以不要把秘密信息放在這個部分。這個 JSON 對象也要使用 Base64URL 算法轉成字符串。

3.Signature 簽名

Signature 部分是對前兩部分的簽名,防止數據篡改。

首先,需要指定一個密鑰(secret)。這個密鑰只有服務器才知道,不能泄露給用戶。然后,使用 Header 里面指定的簽名算法(默認是 HMAC SHA256),按照下面的公式產生簽名。

HMACSHA256(
 base64UrlEncode(header) + "." +
 base64UrlEncode(payload),
 secret)

簽名用于驗證消息在此過程中未被更改,并且,在使用私鑰簽名的令牌的情況下,它還可以驗證JWT的發件人是否是它所聲稱的人。  

把他們三個全部放在一起

輸出是三個由點分隔的Base64-URL字符串,可以在HTML和HTTP環境中輕松傳遞,而與基于XML的標準(如SAML)相比更加緊湊。

下面顯示了一個JWT,它具有先前的頭和​​有效負載編碼,并使用機密簽名。

如果您想使用JWT并將這些概念付諸實踐,您可以使用jwt.io Debugger來解碼,驗證和生成JWT。

【JSON Web令牌如何工作?】

在身份驗證中,當用戶使用其憑據成功登錄時,將返回JSON Web令牌。由于令牌是憑證,因此必須非常小心以防止出現安全問題。一般情況下,您不應該將令牌保留的時間超過要求。

每當用戶想要訪問受保護的路由或資源時,用戶代理應該使用承載模式發送JWT,通常在Authorization標頭中。標題的內容應如下所示:

Authorization: Bearer <token>

在某些情況下,這可以是無狀態授權機制。服務器的受保護路由將檢查Authorization標頭中的有效JWT,如果存在,則允許用戶訪問受保護資源。如果JWT包含必要的數據,則可以減少查詢數據庫以進行某些操作的需要,盡管可能并非總是如此。

如果在標Authorization頭中發送令牌,則跨域資源共享(CORS)將不會成為問題,因為它不使用cookie。

下圖顯示了如何獲取JWT并用于訪問API或資源:

應用程序向授權服務器請求授權校驗用戶身份,校驗成功,返回token應用程序使用訪問令牌訪問受保護的資源【ASP.Net Core 集成JWT】

前面我們介紹了JWT的原理,下面我們在asp.net core實際項目中集成JWT。

首先我們新建一個Demo asp.net core 空web項目

添加數據訪問模擬api,ValuesController

其中api/value1是可以直接訪問的,api/value2添加了權限校驗特性標簽 [Authorize]

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace Demo.Jwt.Controllers
{
  [ApiController]
  public class ValuesController : ControllerBase
  {
    [HttpGet]
    [Route("api/value1")]
    public ActionResult<IEnumerable<string>> Get()
    {
      return new string[] { "value1", "value1" };
    }

    [HttpGet]
    [Route("api/value2")]
    [Authorize]
    public ActionResult<IEnumerable<string>> Get2()
    {
      return new string[] { "value2", "value2" };
    }
  }
}

添加模擬登陸,生成Token的api,AuthController

這里模擬一下登陸校驗,只驗證了用戶密碼不為空即通過校驗,真實環境完善校驗用戶和密碼的邏輯。

using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;

namespace Demo.Jwt.Controllers
{
  [Route("api/[controller]")]
  [ApiController]
  public class AuthController : ControllerBase
  {
    [AllowAnonymous]
    [HttpGet]
    public IActionResult Get(string userName, string pwd)
    {
      if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(pwd))
      {
        var claims = new[]
        {
          new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}") ,
          new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddMinutes(30)).ToUnixTimeSeconds()}"),
          new Claim(ClaimTypes.Name, userName)
        };
        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Const.SecurityKey));
        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
        var token = new JwtSecurityToken(
          issuer: Const.Domain,
          audience: Const.Domain,
          claims: claims,
          expires: DateTime.Now.AddMinutes(30),
          signingCredentials: creds);

        return Ok(new
        {
          token = new JwtSecurityTokenHandler().WriteToken(token)
        });
      }
      else
      {
        return BadRequest(new { message = "username or password is incorrect." });
      }
    }
  }
}

Startup添加JWT驗證的相關配置

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Text;


namespace Demo.Jwt
{
  public class Startup
  {
    public Startup(IConfiguration configuration)
    {
      Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
      //添加jwt驗證:
      services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options => {
          options.TokenValidationParameters = new TokenValidationParameters
          {
            ValidateIssuer = true,//是否驗證Issuer
            ValidateAudience = true,//是否驗證Audience
            ValidateLifetime = true,//是否驗證失效時間
            ClockSkew = TimeSpan.FromSeconds(30),
            ValidateIssuerSigningKey = true,//是否驗證SecurityKey
            ValidAudience = Const.Domain,//Audience
            ValidIssuer = Const.Domain,//Issuer,這兩項和前面簽發jwt的設置一致
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Const.SecurityKey))//拿到SecurityKey
          };
        });

      services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
      ///添加jwt驗證
      app.UseAuthentication();

      if (env.IsDevelopment())
      {
        app.UseDeveloperExceptionPage();
      }

      app.UseMvc(routes =>
      {
        routes.MapRoute(
          name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
      });
    }
  }
}

最后把代碼里面用到的一些相關常量也粘貼過來,Const.cs

namespace Demo.Jwt
{
  public class Const
  {
    /// <summary>
    /// 這里為了演示,寫死一個密鑰。實際生產環境可以從配置文件讀取,這個是用網上工具隨便生成的一個密鑰
    /// </summary>
    public const string SecurityKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDI2a2EJ7m872v0afyoSDJT2o1+SitIeJSWtLJU8/Wz2m7gStexajkeD+Lka6DSTy8gt9UwfgVQo6uKjVLG5Ex7PiGOODVqAEghBuS7JzIYU5RvI543nNDAPfnJsas96mSA7L/mD7RTE2drj6hf3oZjJpMPZUQI/B1Qjb5H3K3PNwIDAQAB";
    public const string Domain = "http://localhost:5000";
  }
}

到這里,已經是我們項目的所有代碼了。

如果需要完整的項目代碼,Github地址:https://github.com/sevenTiny/Demo.Jwt

【JWT測試】

我們找一個趁手的工具,比如fiddler,然后把我們的web站點運行起來

首先調用無權限的接口:http://localhost:5000/api/value1

正確地返回了數據,那么接下來我們測試JWT的流程

1. 無權限

首先我們什么都不加調用接口:http://localhost:5000/api/value2

返回了狀態碼401,也就是未經授權:訪問由于憑據無效被拒絕。 說明JWT校驗生效了,我們的接口收到了保護。

2.獲取Token

調用模擬登陸授權接口:http://localhost:5000/api/Auth?userName=zhangsan&pwd=123

這里的用戶密碼是隨便寫的,因為我們模擬登陸只是校驗了下非空,因此寫什么都能通過

成功得到了響應

然后我們得到了一個xxx.yyy.zzz 格式的 token 值。我們把token復制出來

3.在剛才401的接口請求HEADER中添加JWT的參數,把我們的token加上去

再次調用我們的模擬數據接口,但是這次我們加了一個HEADER:http://localhost:5000/api/value2

把內容粘出來

User-Agent: Fiddler
Host: localhost:5000
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOiIxNTYwMzQ1MDIxIiwiZXhwIjoxNTYwMzQ2ODIxLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiemhhbmdzYW4iLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjUwMDAiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjUwMDAifQ.x7Slk4ho1hZc8sR8_McVTB6VEYLz_v-5eaHvXtIDS-o

這里需要注意Bearer 后面是有一個空格的,然后就是我們上一步獲取到的token

嗯,沒有401了,成功返回了數據

4.JWT的Token過期

我們且倒一杯開水,坐等30分鐘(我們代碼中設置的過期時間),然后再次調用數據接口:http://localhost:5000/api/value2

又變成了401,我們看下詳細的返回數據

這里有標注,錯誤描述 token過期,說明我們設置的token過期時間生效了

【結束】

到這里,我們JWT的簡介以及asp.net core 集成JWT已經完美完成,當然了這只是一個demo,在實際的應用中需要補充和完善的地方還有很多。

如果想要完整項目源碼的,可以參考地址:https://github.com/sevenTiny/Demo.Jwt

如果有幸能幫助到你,高抬貴手點個star吧~

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對腳本之家的支持。

您可能感興趣的文章:

  • asp net core 2.1中如何使用jwt(從原理到精通)
  • asp net core2.1如何使用jwt從原理到精通(二)
  • Asp.Net Core基于JWT認證的數據接口網關實例代碼
  • .net core webapi jwt 更為清爽的認證詳解

相關文章

  • asp.net core集成JWT的步驟記錄

    asp.net core集成JWT的步驟記錄

    【什么是JWT】 JSON Web Token(JWT)是目前最流行的跨域身份驗證解決方案。 JWT的官網地址:https://jwt.io/ 通俗地來講,JWT是能代表用戶身份的令牌,可以使
    2019-06-25
  • VsCode插件開發之插件初步通信的方法步驟

    VsCode插件開發之插件初步通信的方法步驟

    參考了Egret Wing,想像Egret Wing那樣在上方titlebar最右邊上面增加一個menu(這個menu相對于一個按鈕,當點擊這個按鈕時會出現一個window彈框,這個window彈
    2019-06-25
  • VS2015+Qt5+OpenCV3開發環境配置

    VS2015+Qt5+OpenCV3開發環境配置

    本文介紹如何使用VS2015作為編譯開發環境,調用OpenCV3.31和Qt5.9.1寫圖像處理的GUI。 1.目錄結構 假設我們要創建一個名為VideoZoom的工程,那么首先按下圖構
    2019-06-25
  • python爬蟲之自制英漢字典

    python爬蟲之自制英漢字典

    最近在微信公眾號中看到有人用Python做了一個爬蟲,可以將輸入的英語單詞翻譯成中文,或者把中文詞語翻譯成英語單詞。筆者看到了,覺得還蠻有意思的,因此,決
    2019-06-25
  • redis實現分布式的方法總結

    redis實現分布式的方法總結

    一 為什么使用 Redis 在項目中使用 Redis,主要考慮兩個角度:性能和并發。如果只是為了分布式鎖這些其他功能,還有其他中間件 Zookpeer 等代替,并非一定要使
    2019-06-25
  • VsCode之使用WebView通信詳解

    VsCode之使用WebView通信詳解

    之前我在這篇文章VsCode插件開發之插件初步通信 通過插件完成通信,這回我還是通過插件,只不過方式主要以在ts文件里面使用webview來進行通信。 另外在此聲明
    2019-06-25
  • 微信小程序調用天氣接口并且渲染在頁面過程詳解

    微信小程序調用天氣接口并且渲染在頁面過程詳解

    前兩天寫了關于組件庫 iView Weapp的教程,其實也就是把文檔上的例子拿出來體驗了一遍,今天寫一個具體的例子,調用一個免費的天氣接口的api,并且把所獲取的
    2019-06-25
  • 詳解python編譯器和解釋器的區別

    詳解python編譯器和解釋器的區別

    高級語言不能直接被機器所理解執行,所以都需要一個翻譯的階段,解釋型語言用到的是解釋器,編譯型語言用到的是編譯器。 編譯型語言通常的執行過程是:源代碼
    2019-06-25
  • python二維碼操作:對QRCode和MyQR入門詳解

    python二維碼操作:對QRCode和MyQR入門詳解

    python是所有編程語言中模塊最豐富的 生活中常見的二維碼功能在使用python第三方庫來生成十分容易 三個大矩形是定位圖案,用于標記二維碼的大小。這三個定位
    2019-06-25
  • VS2017調用MySQL 8.0的方法

    VS2017調用MySQL 8.0的方法

    本文實例為大家分享了VS2017調用MySQL 8.0的具體方法,供大家參考,具體內容如下 簡述 在網上找了一些解答,發現都有些小問題。 就自己寫一個吧 配置 配置很關
    2019-06-25

最新評論

二分时时彩规律