.NET core webApi 使用JWT驗證簽名

来源:https://www.cnblogs.com/xiaojinFat/archive/2020/07/20/13345685.html
-Advertisement-
Play Games

一、為什麼使用JWT 1.跨語言使用。 2.伺服器端無需再保存任何東西,只需要客戶端保存token就可以。 3.實現簡單。 4.統一認證方式,如果是移動端也要驗證的話,jwt也支持就無需修改,否則客戶端 伺服器一套,移動端 伺服器又是一套 當然缺陷也是很明顯,就是退出登錄後,已發放的token無法銷 ...


一、為什麼使用JWT

1.跨語言使用。

2.伺服器端無需再保存任何東西,只需要客戶端保存token就可以。

3.實現簡單。

4.統一認證方式,如果是移動端也要驗證的話,jwt也支持就無需修改,否則客戶端 伺服器一套,移動端 伺服器又是一套

當然缺陷也是很明顯,就是退出登錄後,已發放的token無法銷毀,可以繼續訪問。就是令牌給你了,如果別人盜取了你的令牌,我也是認的,我只認令牌不認人。也可以設置令牌有效期,假如設置過期有效時間為10分鐘,就算你拿到了令牌想用也已經過期了,但是這就要求客戶端每次想要做什麼,先去申請令牌,然後在去操作,這就很麻煩。內部系統的話是可以用這種模式的,如果對外的不建議使用。對外的可以使用傳統的簽名認證方法。

二、在.net core webApi 搭建jwt並且使用

第一步:首先要在程式中讀取appSettings配置文件信息

創建一個AppSettings.cs類,存放讀取配置信息的函數 代碼如下,使用Nuget  安裝Microsoft.Extensions.Configuration和Microsoft.Extensions.Configuration.Json,Microsoft.Extensions.Configuration.Binder

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Json;
using System;
using System.Collections.Generic;
using System.Linq;

namespace WebApi.Core.Common
{
    public class AppSettings
    {
        static IConfiguration Configuration { get; set; }
        static string contentPath { get; set; }

        public AppSettings(string contentPath)
        {
            string Path = "appsettings.json";

            //如果你把配置文件 是 根據環境變數來分開了,可以這樣寫
            //Path = $"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json";

            Configuration = new ConfigurationBuilder()
               .SetBasePath(contentPath)
               .Add(new JsonConfigurationSource { Path = Path, Optional = false, ReloadOnChange = true })//這樣的話,可以直接讀目錄里的json文件,而不是 bin 文件夾下的,所以不用修改複製屬性
               .Build();
        }

        public AppSettings(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        /// <summary>
        /// 封裝要操作的字元
        /// </summary>
        /// <param name="sections">節點配置</param>
        /// <returns></returns>
        public static string app(params string[] sections)
        {
            try
            {

                if (sections.Any())
                {
                    return Configuration[string.Join(":", sections)];
                }
            }
            catch (Exception)
            {

            }

            return "";
        }

        /// <summary>
        /// 遞歸獲取配置信息數組
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sections"></param>
        /// <returns></returns>
        public static List<T> app<T>(params string[] sections)
        {
            List<T> list = new List<T>();
            Configuration.Bind(string.Join(":", sections), list);
            return list;
        }
    }
}

找到webApi項目,打開Startup類,在ConfigureService函數 註冊AppSettings

 

 

 編輯appsettings.json,新增紅色框子的內容。

 

 

 獲取調試一下

            //註冊appsettings讀取類
            services.AddSingleton(new Appsettings(Configuration));
            var text = Appsettings.app(new string[] { "AppSettings", "ConnectionStringSql" });
            Console.WriteLine($"ConnectionString:{text}");
            Console.ReadLine();    

運行後的結果

 

 

 接下來,我們開始正式的在項目中,註冊和使用JWT,首先配置一下jwt需要的參數,在appsettings.json中,SecretKey必須大於16個,是大於,不是大於等於

 

 

 

 在Api項目中 添加Nuget 包 IdentityModel,Microsoft.AspNetCore.Authentication.JwtBearer,Microsoft.AspNetCore.Authorization 

 

 

 在model項目中添加一個tokenModel

using System;
using System.Collections.Generic;
using System.Text;

namespace WebApi.Core.Model
{
    /// <summary>
    /// 令牌
    /// </summary>
    public class TokenModel
    {
        /// <summary>
        /// Id
        /// </summary>
        public string Uid { get; set; }
        /// <summary>
        /// 角色
        /// </summary>
        public string Role { get; set; }

    }
}

在Api項目中新建一個文件夾 Authorization,新建一個JwtHelper  裡面有生成token 和解析token 兩個方法

using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using WebApi.Core.Common;
using WebApi.Core.Model;

namespace WebApi.Core.Api.Authorization
{
    public class JwtHelper
    {
        /// <summary>
        /// 獲取token信息
        /// </summary>
        /// <param name="tokenModel"></param>
        /// <returns></returns>
        public static string issueJwt(TokenModel tokenModel)
        {
            //獲取Appsetting配置信息
            string iss = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "Issuer" });
            string aud = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "Audience" });
            string secret = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "SecretKey" });

            var claims = new List<Claim>
                {
                 /*
                 * 特別重要:
                   1、這裡將用戶的部分信息,比如 uid 存到了Claim 中,如果你想知道如何在其他地方將這個 uid從 Token 中取出來,
              請看下邊的SerializeJwt() 方法,或者在整個解決方案,搜索這個方法,看哪裡使用了! 2、你也可以研究下 HttpContext.User.Claims ,具體的你可以看看 Policys/PermissionHandler.cs 類中是如何使用的。
*/

          //nbf 生效時間 、Jti 編號、iat 簽發時間、aud 受眾、exp 過期時間
new Claim(JwtRegisteredClaimNames.Jti, tokenModel.Uid.ToString()), new Claim(JwtRegisteredClaimNames.Iat, $"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}"), new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}") , //這個就是過期時間,目前是過期1000秒,可自定義,註意JWT有自己的緩衝過期時間 new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddSeconds(1000)).ToUnixTimeSeconds()}"), new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(1000).ToString()), new Claim(JwtRegisteredClaimNames.Iss,iss), new Claim(JwtRegisteredClaimNames.Aud,aud), }; // 可以將一個用戶的多個角色全部賦予; claims.AddRange(tokenModel.Role.Split(',').Select(s => new Claim(ClaimTypes.Role, s))); //秘鑰 (SymmetricSecurityKey 對安全性的要求,密鑰的長度太短會報出異常) var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret)); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var jwt = new JwtSecurityToken( issuer: iss, claims: claims, signingCredentials: creds); var jwtHandler = new JwtSecurityTokenHandler(); var encodedJwt = jwtHandler.WriteToken(jwt); return encodedJwt; } /// <summary> /// 解析 /// </summary> /// <param name="jwtStr"></param> /// <returns></returns> public static TokenModel SerializeJwt(string jwtStr) { var jwtHandler = new JwtSecurityTokenHandler(); JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr); object role; try { jwtToken.Payload.TryGetValue(ClaimTypes.Role, out role); } catch (Exception e) { Console.WriteLine(e); throw; } var tm = new TokenModel { Uid = jwtToken.Id.ToString(), Role = role != null ? role.ToString() : "", }; return tm; } } }

在UserController 新建一個login介面,獲取token

        /// <summary>
        /// 登錄驗證並且獲取token
        /// </summary>
        /// <param name="loginModel"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult LoginValidate(LoginModel loginModel)
        {
            string jwtStr = string.Empty;
            bool suc = false;

            if (loginModel != null)
            {
                //加登錄驗證
                if (loginModel.UserName == "admin" && loginModel.PassWord == "123456")
                {
                    TokenModel tokenModel = new TokenModel { Uid = loginModel.UserName, Role = loginModel.Role };
                    jwtStr = JwtHelper.issueJwt(tokenModel);
                    suc = true;
                }
            }

            return Ok(new { 
                success=suc,
                token = jwtStr
            });
        }

按F5啟動,可以看到token已經生成,客戶端也已經獲取到。

 

 

 

獲取到了token我們怎麼使用呢? 下一步 我們要在Swagger中開啟 JWT服務,先安裝包 Swashbuckle.AspNetCore.Filters

然後找到SwaggerSetUp.cs的AddSwaggerSetUp方法中增加以下代碼

 public static void AddSwaggerSetup(this IServiceCollection services)
        {
            if (services == null) throw new ArgumentNullException(nameof(services));

            var ApiName = "Webapi.Core";

            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("V1", new OpenApiInfo
                {
                    // {ApiName} 定義成全局變數,方便修改
                    Version = "V1",
                    Title = $"{ApiName} 介面文檔——Netcore 3.0",
                    Description = $"{ApiName} HTTP API V1",

                });
                c.OrderActionsBy(o => o.RelativePath);

                // 獲取xml註釋文件的目錄
                var xmlPath = Path.Combine(AppContext.BaseDirectory, "WebApi.Core.Api.xml");
                c.IncludeXmlComments(xmlPath, true);//預設的第二個參數是false,這個是controller的註釋,記得修改

                // 獲取xml註釋文件的目錄
                var xmlPathModel = Path.Combine(AppContext.BaseDirectory, "WebApi.Core.Model.xml");
                c.IncludeXmlComments(xmlPathModel, true);//預設的第二個參數是false,這個是controller的註釋,記得修改

                //在 header中添加token,傳遞到後臺
                c.OperationFilter<SecurityRequirementsOperationFilter>();

                #region Token綁定到configureServices

                c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
                {
                    Description = "JWT授權(數據將在請求頭中進行傳輸) 直接在下框中輸入Bearer {token}(註意兩者之間是一個空格)\"",
                    Name = "Authorization",//jwt預設的參數名稱
                    In = ParameterLocation.Header,//jwt預設存放Authorization信息的位置(請求頭中)
                    Type = SecuritySchemeType.ApiKey
                });
                #endregion

            });

        }

按F5運行 可以看到 token入口了,按要求的格式在 value中輸入 token 以後的請求head 就會一直加入token了。

 

 

 

 下麵該授權token 的認證了,在SetupService 文件夾下 新建一個AuthJwtSetup.cs 類 如下

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WebApi.Core.Common;

namespace WebApi.Core.Api.SetUpService
{
    public static class AuthJwtSetup
    {
        public static void AddAuthorizationJwtSetUp(this IServiceCollection services)
        {
            if (services == null) throw new ArgumentNullException(nameof(services));

            //讀取配置文件
            var symmetricKeyAsBase64 = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "SecretKey" });
            var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
            var signingKey = new SymmetricSecurityKey(keyByteArray);
            var Issuer = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "Issuer" });
            var Audience = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "Audience" });



            // 令牌驗證參數
            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = signingKey,
                ValidateIssuer = true,
                ValidIssuer = Issuer,//發行人
                ValidateAudience = true,
                ValidAudience = Audience,//訂閱人
                ValidateLifetime = true,
                ClockSkew = TimeSpan.FromSeconds(30), //token過期後 還可以繼續多訪問30秒
                RequireExpirationTime = true,
            };

            //2.1【認證】、core自帶官方JWT認證
            // 開啟Bearer認證
            services.AddAuthentication("Bearer")
             // 添加JwtBearer服務
             .AddJwtBearer(o =>
             {
                 o.TokenValidationParameters = tokenValidationParameters;
                 o.Events = new JwtBearerEvents
                 {
                     OnAuthenticationFailed = context =>
                     {
                         // 如果過期,則把<是否過期>添加到,返回頭信息中
                         if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                         {
                             context.Response.Headers.Add("Token-Expired", "true");
                         }
                         return Task.CompletedTask;
                     }
                 };
             });
        }
    }
}

startup.cs的ConfigureServices 方法添加 服務註入

//jwt授權驗證
services.AddAuthorizationSetup();

 

Configure方法添加 下麵的代碼

 

介面授權策略驗證,在UserController裡面添加一個方法 

 

 按F5啟動調試,先獲取Admin角色許可權的token,添加token到header中,然後請求 驗證角色許可權那個介面,驗證成功。

 

 

 

 

 

 如果獲取的token 不是Admin 角色許可權我們再來試一下,看看是什麼結果,結果就是沒有訪問許可權。

 

 

 

 下麵該解析Token 了,試一下,添加一個介面,步驟同上,先獲取token,然後綁定token,最後調用一下解析介面,看結果我們已經解析成功了。

 

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • JDBC 獲取自增長id以及表的元數據 步驟 1 : 獲取自增長id 在Statement通過execute或者executeUpdate執行完插入語句後,MySQL會為新插入的數據分配一個自增長id,(前提是這個表的id設置為了自增長,在Mysql創建表的時候,AUTO_INCREMENT就表示自 ...
  • from typing import List# 這道題很容易能夠想到,只需要遍歷兩邊列表就可以了# 兩層迴圈class Solution: def twoSum(self, numbers: List[int], target: int) -> List[int]: # 第一次遍歷列表 for i ...
  • 作者:我恰芙蓉王 原文:https://www.cnblogs.com/-tang/p/13283216.html 業務場景 在很多項目中,都有類似數據彙總的業務場景,查詢今日註冊會員數,線上會員數,訂單總金額,支出總金額等。。。這些業務通常都不是存在同一張表中,我們需要依次查詢出來然後封裝成所需要 ...
  • 今天的學習內容,老師就給我們上了一份大餐,電腦的 進位 ,當然我們學習肯定不會像百度百科那樣的一點點的詳細的去瞭解。畢竟我們學習的是java語言,所以根據java的內容來學二進位的。(內容與標題不太相同見諒啊QAQ,我也不知道該取啥標題) 基本數據類型: 數據類型關鍵字記憶體占用取值範圍 位元組型 b ...
  • 前言 本文的文字及圖片來源於網路,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯繫我們以作處理 1.迭代器 迭代是Python最強大的功能之一,是訪問集合元素的一種方式。 迭代器是一個可以記住遍歷的位置的對象。 迭代器對象從集合的第一個元素開始訪問,直到所有的元素被訪問完 ...
  • 前言 本文的文字及圖片來源於網路,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯繫我們以作處理。 作者:慄科技 一、爬取介紹 利用Chrome瀏覽器抓包可知,B站的彈幕文件以XML文檔式進行儲存,如下所示(共三千條實時彈幕) 其URL為: http://comment.b ...
  • 值類型取值範圍、與運算(&)、或運算(|)、非運算(~)、異或運算(^)、位運算和位枚舉。 ...
  • 創建型設計模式總結 Intro 前面幾篇文章已經把創建型設計模式都介紹了,來做一個簡單的總結。 創建型設計模式,就是用來創建對象的設計模式,根據要創建的對象的複雜度以及是否允許多實例以及是否需要容易擴展等多方面考慮去選擇合適的設計模式來創建對象。 Summary 單例模式(Singleton) 需要 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...