主頁 > .NET開發 > .NET core webApi 使用JWT驗證簽名

.NET core webApi 使用JWT驗證簽名

2020-09-10 09:35:28 .NET開發

一、為什么使用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,最后呼叫一下決議介面,看結果我們已經決議成功了,

 

 

 

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/1653.html

標籤:.NET Core

上一篇:.NET core 使用Swagger

下一篇:因為喜歡所以升級,MyStaging-3.0 繼續

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more