.Net Core官方JWT授權(quán)驗(yàn)證的全過程
什么是JWT?
JSON Web令牌(JWT)是一個(gè)開放標(biāo)準(zhǔn)(RFC 7519),它定義了一種緊湊且自包含的方式,用于在各方之間安全地傳輸信息作為JSON對象。由于此信息是經(jīng)過數(shù)字簽名的,因此可以被驗(yàn)證和信任??梢允褂妹孛埽ㄊ褂肏MAC算法)或使用RSA或ECDSA的公鑰/私鑰對對JWT進(jìn)行簽名。
盡管可以對JWT進(jìn)行加密以提供雙方之間的保密性,但我們將重點(diǎn)關(guān)注已簽名的令牌。簽名的令牌可以驗(yàn)證其中包含的聲明的完整性,而加密的令牌則將這些聲明隱藏在其他方的面前。當(dāng)使用公鑰/私鑰對對令牌進(jìn)行簽名時(shí),簽名還證明只有持有私鑰的一方才是對其進(jìn)行簽名的一方。由于缺乏安全性,所以不能把如密碼等敏感信息放在令牌中。
什么時(shí)候應(yīng)該使用JWT?
以下是JSON Web令牌有用的一些情況:
- 授權(quán):這是使用JWT的最常見方案。一旦用戶登錄,每個(gè)后續(xù)請求將包括JWT,從而允許用戶訪問該令牌允許的路由,服務(wù)和資源。單一登錄是當(dāng)今廣泛使用JWT的一項(xiàng)功能,因?yàn)樗拈_銷很小并且可以在不同的域中輕松使用。
- 信息交換:JSON Web令牌是在各方之間安全傳輸信息的好方法。因?yàn)榭梢詫WT進(jìn)行簽名(例如,使用公鑰/私鑰對),所以您可以確定發(fā)件人是他們所說的人。此外,由于簽名是使用標(biāo)頭和有效負(fù)載計(jì)算的,因此您還可以驗(yàn)證內(nèi)容是否未被篡改。
JWT結(jié)構(gòu)是什么?
JSON Web令牌以緊湊的形式由三部分組成,這些部分由點(diǎn)(.)分隔,分別是:
- 標(biāo)頭
- 有效載荷
- 簽名
因此,JWT通常如下所示。
xxxxx.yyyyy.zzzzz
標(biāo)頭:通常由兩部分組成,令牌類型和使用的簽名算法。
{ "alg": "HS256", "typ": "JWT" }
有效載荷:有三種說明類型,預(yù)定義聲明、公共聲明和私有聲明。聲明名稱僅是三個(gè)字符,因?yàn)镴WT是緊湊的
- 預(yù)定義聲明:包括iss(發(fā)出者), exp(到期時(shí)間), sub(主題), aud(受眾)等,是推薦的但是不是強(qiáng)制的可以沒有。
- 公共聲明:公共聲明,這個(gè)部分可以隨便定義,但是要注意和 IANA JSON Web Token 沖突。
- 私有聲明:這個(gè)部分是共享被認(rèn)定信息中自定義部分。
簽名:要創(chuàng)建簽名部分,您必須獲取編碼的標(biāo)頭,編碼的有效負(fù)載,機(jī)密,標(biāo)頭中指定的算法,并對其進(jìn)行簽名。
例如,如果要使用HMAC SHA256算法,則將通過以下方式創(chuàng)建簽名:
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
簽名用于驗(yàn)證消息在此過程中沒有更改,并且對于使用私鑰進(jìn)行簽名的令牌,它還可以驗(yàn)證JWT的發(fā)送者是它所說的真實(shí)身份。
組合在一起如下為輸出是三個(gè)由點(diǎn)分隔的Base64-URL字符串:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjUyMDAiLCJhdWQiOlsiYXBpIiwiYXBpIl0sIkd1aWQiOiIzM2NhZmJkNS1jZWEyLTRjOWMtYWZlYS01MDYyZjM3YWUyOTAiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOlsic3lzdGVtIiwiYWRtaW4iXSwiZXhwIjoxNjA2NjU2NjI0fQ. JvDHuowbOnWiyxMIFc9gG5rw1LSSc0xx68L31oRfxS0
如何使用JWT
每當(dāng)用戶想要訪問受保護(hù)的路由或資源時(shí),用戶代理都應(yīng)發(fā)送JWT,通常使用承載模式在Authorization標(biāo)頭中發(fā)送JWT 。標(biāo)頭的內(nèi)容應(yīng)如下所示:
Authorization: Bearer <token>
在某些情況下,這可以是無狀態(tài)授權(quán)機(jī)制。服務(wù)器的受保護(hù)路由將在Authorization標(biāo)頭中檢查有效的JWT ,如果存在,則將允許用戶訪問受保護(hù)的資源。如果JWT包含必要的數(shù)據(jù),則可以減少查詢數(shù)據(jù)庫中某些操作的需求,盡管這種情況并非總是如此。
如果令牌是在Authorization標(biāo)頭中發(fā)送的,則跨域資源共享(CORS)不會成為問題,因?yàn)樗皇褂胏ookie。
下圖顯示了如何獲取JWT并將其用于訪問API或資源:
- 應(yīng)用程序或客戶端向授權(quán)服務(wù)器請求授權(quán)。這是通過不同的授權(quán)流程之一執(zhí)行的。例如,典型的符合OpenID Connect的Web應(yīng)用程序?qū)?oauth/authorize使用授權(quán)代碼流通過端點(diǎn)。
- 授予授權(quán)后,授權(quán)服務(wù)器會將訪問令牌返回給應(yīng)用程序。
- 該應(yīng)用程序使用訪問令牌來訪問受保護(hù)的資源(例如API)。
請注意,使用簽名的令牌,令牌中包含的所有信息都會暴露給用戶或其他方,即使他們無法更改它。這意味著您不應(yīng)將機(jī)密信息放入令牌中。
.net core的JWT驗(yàn)證授權(quán)
我們直接新建一個(gè).net core webapi的項(xiàng)目,我這里版本是3.1的
1. 先使用nuget安裝:Microsoft.AspNetCore.Authentication.JwtBearer。注意版本和.net core版本的兼容。net5的支持5.0.0+的版本,否則就用對應(yīng)可以用的低版本吧。
2. 在appsettings.json配置文件中寫好我們的 JWT 的配置參數(shù)如下:
"Jwt": { "Secret": "your-256-bit-secret", "Iss": "https://localhost:44355", "Aud": "api" }
3. 在Startup.cs的ConfigureServices方法中添加授權(quán)認(rèn)證如下:
var jwtConfig = Configuration.GetSection("Jwt"); //生成密鑰 var symmetricKeyAsBase64 = jwtConfig.GetValue<string>("Secret"); var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64); var signingKey = new SymmetricSecurityKey(keyByteArray); //認(rèn)證參數(shù) services.AddAuthentication("Bearer") .AddJwtBearer(o => { o.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true,//是否驗(yàn)證簽名,不驗(yàn)證的畫可以篡改數(shù)據(jù),不安全 IssuerSigningKey = signingKey,//解密的密鑰 ValidateIssuer = true,//是否驗(yàn)證發(fā)行人,就是驗(yàn)證載荷中的Iss是否對應(yīng)ValidIssuer參數(shù) ValidIssuer = jwtConfig.GetValue<string>("Iss"),//發(fā)行人 ValidateAudience = true,//是否驗(yàn)證訂閱人,就是驗(yàn)證載荷中的Aud是否對應(yīng)ValidAudience參數(shù) ValidAudience = jwtConfig.GetValue<string>("Aud"),//訂閱人 ValidateLifetime = true,//是否驗(yàn)證過期時(shí)間,過期了就拒絕訪問 ClockSkew = TimeSpan.Zero,//這個(gè)是緩沖過期時(shí)間,也就是說,即使我們配置了過期時(shí)間,這里也要考慮進(jìn)去,過期時(shí)間+緩沖,默認(rèn)好像是7分鐘,你可以直接設(shè)置為0 RequireExpirationTime = true, }; });
在Configure方法中添加 app.UseAuthentication() 和 app.UseAuthorization() 注意位置需要放置的位置:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()){app.UseDeveloperExceptionPage();} app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints =>{ endpoints.MapControllers();}); }
4. 生成jwt令牌,在默認(rèn)生成的控制器 WeatherForecastController 中添加如下生成令牌的方法:
[HttpPost] public IActionResult Authenticate() { var jwtConfig = Configuration.GetSection("Jwt"); //秘鑰,就是標(biāo)頭,這里用Hmacsha256算法,需要256bit的密鑰 var securityKey = new SigningCredentials(new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwtConfig.GetValue<string>("Secret"))), SecurityAlgorithms.HmacSha256); //Claim,JwtRegisteredClaimNames中預(yù)定義了好多種默認(rèn)的參數(shù)名,也可以像下面的Guid一樣自己定義鍵名. //ClaimTypes也預(yù)定義了好多類型如role、email、name。Role用于賦予權(quán)限,不同的角色可以訪問不同的接口 //相當(dāng)于有效載荷 var claims = new Claim[] { new Claim(JwtRegisteredClaimNames.Iss,jwtConfig.GetValue<string>("Iss")), new Claim(JwtRegisteredClaimNames.Aud,jwtConfig.GetValue<string>("Aud")), new Claim("Guid",Guid.NewGuid().ToString("D")), new Claim(ClaimTypes.Role,"system"), new Claim(ClaimTypes.Role,"admin"), }; SecurityToken securityToken = new JwtSecurityToken( signingCredentials: securityKey, expires: DateTime.Now.AddMinutes(2),//過期時(shí)間 claims: claims ); //生成jwt令牌 return Content(new JwtSecurityTokenHandler().WriteToken(securityToken)); }
5. 使用jwt控制接口的訪問,我們在一個(gè)接口上添加一個(gè)特性 [Authorize(Roles ="admin")],表示需要有admin這個(gè)角色的jwt令牌才能訪問,沒有roles參數(shù)的話表示只要是可用的令牌就可以訪問,多個(gè)role角色可以疊加多個(gè)特性:
[HttpGet] [Authorize(Roles = "admin")] [Authorize(Roles = "system")] public IEnumerable<WeatherForecast> Get() { var rng = new Random(); return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = rng.Next(-20, 55), Summary = Summaries[rng.Next(Summaries.Length)] }) .ToArray(); }
6.測試,然后我們用postman就可以測試了,可以看到非常成功有數(shù)據(jù)。
進(jìn)階
認(rèn)證的時(shí)候可以添加事件,如下面的認(rèn)證失敗事件、接收參數(shù)事件可以獲取url上的參數(shù)作為令牌而不是通過http的請求頭的Authorization。
services.AddAuthentication("Bearer") .AddJwtBearer(o => { o.Events = new JwtBearerEvents() { OnMessageReceived = context => { context.Token = context.Request.Query["access_token"]; return Task.CompletedTask; }, OnAuthenticationFailed = context => { // 如果過期,則把<是否過期>添加到,返回頭信息中 if (context.Exception.GetType() == typeof(SecurityTokenExpiredException)) { context.Response.Headers.Add("Token-Expired", "true"); } return Task.CompletedTask; } }; });
總結(jié)
到此這篇關(guān)于.Net Core官方JWT授權(quán)驗(yàn)證的文章就介紹到這了,更多相關(guān).Net Core官方JWT授權(quán)驗(yàn)證內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
ASP.NET Core文件壓縮常見使用誤區(qū)(最佳實(shí)踐)
本文給大家分享ASP.NET Core文件壓縮常見的三種誤區(qū),就每種誤區(qū)給大家講解的非常詳細(xì),是項(xiàng)目實(shí)踐的最佳紀(jì)錄,對ASP.NET Core文件壓縮相關(guān)知識感興趣的朋友一起看看吧2021-05-05asp.net XML文件操作實(shí)現(xiàn)代碼
這幾天在項(xiàng)目中用到了XML文件配置存儲一些基本信息,如:參數(shù)、表格等一些信息存儲。由于記錄不是很多,所以用此文件來代替數(shù)據(jù)庫中設(shè)計(jì)的表結(jié)構(gòu)。2009-12-12ASP.NET Core使用SkiaSharp實(shí)現(xiàn)驗(yàn)證碼的示例代碼
本篇文章主要介紹了ASP.NET Core使用SkiaSharp實(shí)現(xiàn)驗(yàn)證碼的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-12-12uniapp+.net?core實(shí)現(xiàn)微信小程序獲取手機(jī)號功能
這篇文章主要介紹了uniapp+.net?core實(shí)現(xiàn)微信小程序獲取手機(jī)號功能,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-08-08asp.net在后端動態(tài)添加樣式表調(diào)用的方法
這篇文章主要介紹了asp.net在后端動態(tài)添加樣式表調(diào)用的方法,涉及asp.net操作樣式表的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-04-04asp.net XMLHttpRequest實(shí)現(xiàn)用戶注冊前的驗(yàn)證
用戶注冊前的驗(yàn)證,提高用戶體驗(yàn)。2009-10-10[譯]ASP.NET Core 2.0 網(wǎng)址重定向的方法
本篇文章主要介紹了[譯]ASP.NET Core 2.0 網(wǎng)址重定向的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10