因為害怕token泄露出現問題,所以從未在項目中使用jwt。但這玩意現在真的很火,趁有空還是研究了一下。
在aspnetcore中實現jwt很簡單,感覺微軟把很多工作都做了,雖然開發效率上去了,但是使得c#的程序員變得很傻,很多事情都是知其然而不知其所以然,只能綁死在微軟這條大船上越行越遠,唉~~
jwt一般在webapi的項目使用比較多,但我下面的代碼都是在MVC環境上測試的,用法上應該沒什么區別。
一、添加和配置JWT
1、引入nuget包
VS中點擊 工具 > 管理解決方案 NuGet 程序包,搜索 IdentityModel,安裝到項目
2、添加JWT配置項
打開 appsettings.json ,添加節點
"Authentication": { "JwtBearer": { "IsEnabled": "true", "SecurityKey": "JWTStudyWebsite_DI20DXU3", "Issuer": "JWTStudy", "Audience": "JWTStudyWebsite" } }
3、新建 JWTConfiguration.cs 文件,內容如下:
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.IdentityModel.Tokens; using System; using System.Text; namespace JWTStudent.Website.Extensions { public static class JwtConfiguration { public static void AddJwtConfiguration(this IServiceCollection services, IConfiguration configuration) { if (bool.Parse(configuration["Authentication:JwtBearer:IsEnabled"])) { services.AddAuthentication(options => { options.DefaultAuthenticateScheme = "JwtBearer"; options.DefaultChallengeScheme = "JwtBearer"; }).AddJwtBearer("JwtBearer", options => { options.Audience = configuration["Authentication:JwtBearer:Audience"]; options.TokenValidationParameters = new TokenValidationParameters { // The signing key must match! ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey( Encoding.ASCII.GetBytes(configuration["Authentication:JwtBearer:SecurityKey"])), // Validate the JWT Issuer (iss) claim ValidateIssuer = true, ValidIssuer = configuration["Authentication:JwtBearer:Issuer"], // Validate the JWT Audience (aud) claim ValidateAudience = true, ValidAudience = configuration["Authentication:JwtBearer:Audience"], // Validate the token expiry ValidateLifetime = true, // If you want to allow a certain amount of clock drift, set that here ClockSkew = TimeSpan.Zero }; }); } } } }
4、在StartUp.cs的ConfigurationServices方法內,添加如下代碼:
services.AddJwtConfiguration(Configuration);
二、創建AccessTokenController,用於申請和發放JWT
public IActionResult Post([FromBody]LoginModel model) { var user = TempData.Users.FirstOrDefault(m => m.Account == model.Account && m.Pw == model.Pw); if (user != null) { var claims = new[] { new Claim(ClaimTypes.Name, user.Account), new Claim(ClaimTypes.Role, user.Role) }; var key = new SymmetricSecurityKey( Encoding.UTF8.GetBytes(_configuration["Authentication:JwtBearer:SecurityKey"])); var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken( _configuration["Authentication:JwtBearer:Issuer"], _configuration["Authentication:JwtBearer:Audience"], claims, expires: DateTime.Now.AddMinutes(30), signingCredentials: credentials ); return Ok(new AccessTokenResult {Token = new JwtSecurityTokenHandler().WriteToken(token), Code = 200}); } return Ok(new AccessTokenResult {Code = 0, Token = ""}); }
LoginModel是自定義的登錄模型,很簡單,僅包含用戶名和密碼兩個字段。AccessTokenResult是自定義的返回結果,int類型的Code,登錄成功則返回200,失敗為0,Token是生成的JWT
三、測試
1、創建TestController,並為其添加 Authorization 描述
2、運行程序,打開Postman,訪問 http://localhost:5000/test
不出所料,訪問被拒絕,提示沒有授權。
3、獲取JWT
訪問 http://localhost:5000/api/accesstoken
4、使用Token重新訪問受限的Action
拷貝token的值,重新請求 http://localhost:5000/test,在Headers上添加一項,KEY 為 Authorization,VALUE 為 Bear+空格+token值