<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Dotnet Core使用JWT認證授權最佳實踐

          共 8136字,需瀏覽 17分鐘

           ·

          2020-07-28 17:16




          最近,團隊的小伙伴們在做項目時,需要用到JWT認證。遂根據(jù)自己的經(jīng)驗,整理成了這篇文章,用來幫助理清JWT認證的原理和代碼編寫操作。

          一、JWT

          JSON Web Token (JWT)是一個開放標準(RFC 7519),它定義了一種緊湊的、自包含的方式,用于作為JSON對象在各方之間安全地傳輸信息。該信息可以被驗證和信任,因為它是數(shù)字簽名的。

          ?

          JWT是什么,看上面這段網(wǎng)上抄來的話。

          關于JWT以及優(yōu)缺點,網(wǎng)上有很多詳細的說法,我這兒就不重復了。

          我們只需要知道以下的事實:

          在一般的系統(tǒng)中,我們有時候會做個用戶登錄。用戶登錄完成進到系統(tǒng)后,需要根據(jù)用戶的權限,來控制一些功能可用,而另一些功能不可用。

          在SOA/AOP架構中,做為最重要的API端,其實也需要有類似登錄或認證的內容,用來區(qū)分哪些用戶可以使用某個API,哪些用戶不行。

          同時,我們希望這個登錄或類似登錄的過程,只發(fā)生在一個固定位置。這樣,在我們寫代碼時,建立好這樣一個過程后,在我們后邊寫代碼時,簡單引用即可,而不需要每個API程序都開發(fā)一次認證。這個需求,其實就是OAuth的由來。

          最重要的是,這樣的代碼寫出來,顯得高大上

          ?

          下面進入正題。

          認證這個操作,就像我們最近的日子。

          首先,我們要有一個出入證,或者綠碼。這個證,我們稱作令牌(Token)。我們去領這個證,這個操作稱為發(fā)行(Issue)。

          我們拿著這個證,去到一個地方。有專人會檢查這個證,這稱為用戶身份驗證(Authentication)。驗證通過放行,稱為授權(Authorization),驗證不通過,叫作未授權錯誤(Unauthorized)。

          如果這個證過期了,你就需要去重新辦一個證。這個過程叫做刷新(RefreshToken)。

          簡言之,這就是認證的全部流程。

          ?

          下面,我用一個Demo項目,來逐步完成這個過程。

          二、開發(fā)環(huán)境&基礎項目

          這個Demo的開發(fā)環(huán)境是:Mac + VS Code + Dotnet Core 3.1.2。

          $?dotnet?--info
          .NET?Core?SDK?(reflecting?any?global.json):
          ?Version:???3.1.201
          ?Commit:????b1768b4ae7

          Runtime?Environment:
          ?OS?Name:?????Mac?OS?X
          ?OS?Version:??10.15
          ?OS?Platform:?Darwin
          ?RID:?????????osx.10.15-x64
          ?Base?Path:???/usr/local/share/dotnet/sdk/3.1.201/

          Host?(useful?for?support):
          ??Version:?3.1.3
          ??Commit:??4a9f85e9f8

          .NET?Core?SDKs?installed:
          ??3.1.201?[/usr/local/share/dotnet/sdk]

          .NET?Core?runtimes?installed:
          ??Microsoft.AspNetCore.App?3.1.3?[/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
          ??Microsoft.NETCore.App?3.1.3?[/usr/local/share/dotnet/shared/Microsoft.NETCore.App]

          ?

          首先,在這個環(huán)境下建立工程:

          1. 創(chuàng)建Solution

          %?dotnet?new?sln?-o?demo
          The?template?"Solution?File"?was?created?successfully.
          1. 用Webapi模板創(chuàng)建項目

          %?cd?demo
          %?dotnet?new?webapi?-o?demo
          The?template?"ASP.NET?Core?Web?API"?was?created?successfully.

          Processing?post-creation?actions...
          Running?'dotnet?restore'?on?demo/demo.csproj...
          ??Restore?completed?in?179.13?ms?for?demo/demo.csproj.

          Restore?succeeded.
          1. 把Demo項目加到Solution中

          %?dotnet?sln?add?demo/demo.csproj
          Project?`demo/demo.csproj`?added?to?the?solution.
          1. 安裝Swagger(這步非必須,我習慣用Swagger,不習慣用Postman)

          %?dotnet?add?package?Swashbuckle.AspNetCore
          log??:?Restore?completed?in?2.75?sec?for?demo/demo.csproj.
          1. 安裝JWT認證支持庫(必須引入)

          %?dotnet?add?package?Microsoft.AspNetCore.Authentication.JwtBearer
          log??:?Restore?completed?in?3.09?sec?for?demo/demo.csproj.

          ?

          五步做完,基礎項目就建完了。

          看一下整個的目錄結構:

          %?tree?.
          .
          ├──?demo
          │???├──?Controllers
          │???│???└──?WeatherForecastController.cs
          │???├──?Program.cs
          │???├──?Properties
          │???│???└──?launchSettings.json
          │???├──?Startup.cs
          │???├──?WeatherForecast.cs
          │???├──?appsettings.Development.json
          │???├──?appsettings.json
          │???├──?demo.csproj
          │???└──?obj
          │???????├──?demo.csproj.nuget.dgspec.json
          │???????├──?demo.csproj.nuget.g.props
          │???????├──?demo.csproj.nuget.g.targets
          │???????├──?project.assets.json
          │???????└──?project.nuget.cache
          └──?demo.sln

          ?

          1. 在Startup.cs中補充代碼,以啟用Swagger

          在ConfigureServices方法中加入以下代碼:

          services.AddSwaggerGen(c?=>
          {
          ????????c.SwaggerDoc("v1",?new?OpenApiInfo?{?Title?=?"Demo",?Version?=?"V1"?});

          ????????c.AddSecurityDefinition("Bearer",?new?OpenApiSecurityScheme
          ????????{
          ????????????????Name?=?"Authorization",
          ????????????????Type?=?SecuritySchemeType.ApiKey,
          ????????????????Scheme?=?"Bearer",
          ????????????????BearerFormat?=?"JWT",
          ????????????????In?=?ParameterLocation.Header,
          ????????????????Description?=?"",
          ????????});

          ????????c.AddSecurityRequirement(new?OpenApiSecurityRequirement
          ????????{
          ????????????????{
          ????????????????????????new?OpenApiSecurityScheme
          ????????????????????????{
          ????????????????????????????????Reference?=?new?OpenApiReference
          ????????????????????????????????{
          ????????????????????????????????????????Type?=?ReferenceType.SecurityScheme,
          ????????????????????????????????????????Id?=?"Bearer"
          ????????????????????????????????}
          ????????????????????????},
          ????????????????????????new?string[]?{}
          ????????????????}
          ????????});
          });

          在Configure方法中加入以下代碼

          app.UseSwagger();
          app.UseSwaggerUI(c?=>
          {
          ????????c.SwaggerEndpoint("/swagger/v1/swagger.json",?"Demo?V1");
          });

          關于Swagger的詳細配置,這里不做說明,留著以后寫。

          三、簽發(fā)Token

          簽發(fā)Token是認證的第一步。

          用戶進到系統(tǒng),在驗證用戶帳號密碼后,需要根據(jù)用戶的數(shù)據(jù),把Token返回給用戶。

          這個過程其實跟認證沒什么關系,只是一個普通的API功能。

          1. 工程下加一個目錄DTOModels,創(chuàng)建一個LoginRequestDTO的類,用于定義API的輸入?yún)?shù)。

          using?System;

          namespace?demo.DTOModels
          {
          ????public?class?LoginRequestDTO
          ????{

          ????????public?string?username?{?get;?set;?}
          ????????public?string?password?{?get;?set;?}
          ????}
          }
          1. 創(chuàng)建一個控制器AuthenticationController,并在控制器里創(chuàng)建一個API方法RequestToken。

          using?Microsoft.AspNetCore.Mvc;
          using?demo.DTOModels;

          namespace?demo.Controllers
          {
          ????public?class?AuthenticationController?:?ControllerBase
          ????{
          ????????[HttpPost,?Route("requesttoken")]
          ????????public?ActionResult?RequestToken([FromBody]?LoginRequestDTO?request)
          ????????
          {
          ??????????????//這兒待完善
          ????????????return?Ok();
          ????????}
          ????}
          }
          1. 生成JWT Token需要預設一些參數(shù)。我們在appsetting.json里先設置好。

          {
          ??"Logging":?{
          ????"LogLevel":?{
          ??????"Default":?"Information",
          ??????"Microsoft":?"Warning",
          ??????"Microsoft.Hosting.Lifetime":?"Information"
          ????}
          ??},
          ??"AllowedHosts":?"*",
          ??"tokenParameter":?{
          ????"secret":?"123456123456123456",
          ????"issuer":?"WangPlus",
          ????"accessExpiration":?120,
          ????"refreshExpiration":?1440
          ??}
          }

          這里,tokenParameter節(jié)是我們設置的參數(shù)。一般來說,是這幾個:

          secret: JWT加密的密鑰。現(xiàn)在主流用SHA256加密,需要256位以上的密鑰,unicode是16個字符以上,盡量復雜一些。密鑰泄露,Token就會被破解,所以,你懂的。

          issuer: 簽發(fā)人的名稱,如果沒人注意,你可以把大名寫在上面。

          accessExpiration: Token的有效分鐘數(shù)。過了這個時間,這個Token會過期。

          refreshExpiration: refreshToken的有效分鐘數(shù)。過了這個時間,用戶需要重新登錄。

          ?

          Token過期后,可以讓用戶重新登錄認證拿Token。但這個方式會比較Low。高大上的方式是簽發(fā)Token的時候,同時也簽發(fā)一個refreshToken給用戶。用戶Token過期后,可以拿refreshToken去申請新的Token,同時刷新refreshToken。如果用戶長時間未使用系統(tǒng),refreshToken也過期了,才讓用戶重新登錄認證。

          refreshToken可以用JWT生成,也可以自己生成,不影響認證。

          1. 建一個Models目錄,創(chuàng)建一個映射tokenParameter的類。這個類不是必須,只是為了寫著方便。不想這樣寫,也可以直接讀配置,再轉成數(shù)據(jù)。

          using?System;

          namespace?demo.Models
          {
          ????public?class?tokenParameter
          ????{

          ????????public?string?Secret?{?get;?set;?}
          ????????public?string?Issuer?{?get;?set;?}
          ????????public?int?AccessExpiration?{?get;?set;?}
          ????????public?int?RefreshExpiration?{?get;?set;?}
          ????}
          }
          1. 在前邊建好的API - RequestToken中,完成Token和refreshToken的生成和返回。

          using?Microsoft.AspNetCore.Mvc;
          using?demo.DTOModels;
          using?Microsoft.Extensions.Configuration;
          using?System;
          using?System.Text;
          using?demo.Models;
          using?Microsoft.IdentityModel.Tokens;
          using?System.Security.Claims;
          using?System.IdentityModel.Tokens.Jwt;

          namespace?demo.Controllers
          {
          ????public?class?AuthenticationController?:?ControllerBase
          ????{
          ????????private?tokenParameter?_tokenParameter?=?new?tokenParameter();
          ????????public?AuthenticationController()
          ????????
          {
          ????????????var?config?=?new?ConfigurationBuilder()
          ????????????????.SetBasePath(AppContext.BaseDirectory)
          ????????????????.AddJsonFile("appsettings.json")
          ????????????????.Build();

          ????????????_tokenParameter?=?config.GetSection("tokenParameter").Get();
          ????????}

          ????????[HttpPost,?Route("requestToken")]
          ????????public?ActionResult?RequestToken([FromBody]?LoginRequestDTO?request)
          ????????
          {
          ????????????//這兒在做用戶的帳號密碼校驗。我這兒略過了。
          ????????????if?(request.username?==?null?&&?request.password?==?null)
          ????????????????return?BadRequest("Invalid?Request");

          ??????????????//生成Token和RefreshToken
          ????????????var?token?=?GenUserToken(request.username,?"testUser");
          ????????????var?refreshToken?=?"123456";

          ????????????return?Ok(new[]?{?token,?refreshToken?});
          ????????}


          ??????????//這兒是真正的生成Token代碼
          ??????????private?string?GenUserToken(string?username,?string?role)
          ????????
          {
          ????????????var?claims?=?new[]
          ????????????{
          ????????????????new?Claim(ClaimTypes.Name,?username),
          ????????????????new?Claim(ClaimTypes.Role,?role),
          ????????????};

          ????????????var?key?=?new?SymmetricSecurityKey(Encoding.UTF8.GetBytes(_tokenParameter.Secret));
          ????????????var?credentials?=?new?SigningCredentials(key,?SecurityAlgorithms.HmacSha256);
          ????????????var?jwtToken?=?new?JwtSecurityToken(_tokenParameter.Issuer,?null,?claims,?expires:?DateTime.UtcNow.AddMinutes(_tokenParameter.AccessExpiration),?signingCredentials:?credentials);

          ????????????var?token?=?new?JwtSecurityTokenHandler().WriteToken(jwtToken);

          ????????????return?token;
          ????????}
          ????}
          }

          這個類里,驗證帳號密碼的代碼我略過了。還有,refreshToken給了一個固定串。真實項目這兒就按需要做就好。

          往期精彩

          2020 年開發(fā)者生態(tài)報告:眾人羨慕的自由職業(yè)者僅占5%,使用C#僅占13%
          Github上優(yōu)秀的.NET Core項目
          為什么需要使用JSON格式記錄日志?
          為什么.NET Web 應用推薦使用 await、async異步編程?
          回復?【關閉】學關閉微信朋友圈廣告
          回復?【實戰(zhàn)】獲取20套實戰(zhàn)源碼
          回復?【福利】獲取最新微信支付有獎勵
          回復?【被刪】學查看你哪個好友刪除了你巧
          回復?【聊天記錄】學備份/恢復聊天記錄
          回復?【訪客】學微信查看朋友圈訪客記錄
          回復?【卡通】學制作微信卡通頭像
          回復?【python】學微獲取全套0基礎Python知識手冊
          瀏覽 48
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  偷拍免费网站 | 亚洲成人性爱影院 | 网址成人视频国产偷拍 | 欧美成人高清在线 | 国产无码电影在线观看 |