.Nrt Core实现JWT Token
2.新建一个JwtHelpers.cs的类将一下内容复制到类中
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Text;
using System.IdentityModel.Tokens.Jwt;
namespace JwtAuthDemo.Helpers
{
public class JwtHelpers
{
private readonly IConfiguration Configuration;
public JwtHelpers(IConfiguration configuration)
{
this.Configuration = configuration;
}
public string GenerateToken(string userName, int expireMinutes = 1440)
{
var issuer = Configuration.GetValue<string>("JwtSettings:Issuer");
var signKey = Configuration.GetValue<string>("JwtSettings:SignKey");
// 設定要加入到 JWT Token 中的聲明資訊(Claims)
var claims = new List<Claim>();
// 在 RFC 7519 規格中(Section#4),總共定義了 7 個預設的 Claims,我們應該只用的到兩種!
claims.Add(new Claim(JwtRegisteredClaimNames.Sub, userName)); // User.Identity.Name
claims.Add(new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())); // JWT ID
// 網路上常看到的這個 NameId 設定是多餘的
//claims.Add(new Claim(JwtRegisteredClaimNames.NameId, userName));
// 這個 Claim 也以直接被 JwtRegisteredClaimNames.Sub 取代,所以也是多餘的
//claims.Add(new Claim(ClaimTypes.Name, userName));
// 你可以自行擴充 "roles" 加入登入者該有的角色
claims.Add(new Claim("roles", "Admin"));
claims.Add(new Claim("roles", "Users"));
var userClaimsIdentity = new ClaimsIdentity(claims);
// 建立一組對稱式加密的金鑰,主要用於 JWT 簽章之用
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(signKey));
// HmacSha256 有要求必須要大於 128 bits,所以 key 不能太短,至少要 16 字元以上
// https://stackoverflow.com/questions/47279947/idx10603-the-algorithm-hs256-requires-the-securitykey-keysize-to-be-greater
var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
// 建立 SecurityTokenDescriptor
var tokenDescriptor = new SecurityTokenDescriptor
{
Issuer = issuer,
//Audience = issuer, // 由於你的 API 受眾通常沒有區分特別對象,因此通常不太需要設定,也不太需要驗證
//NotBefore = DateTime.Now, // 預設值就是 DateTime.Now
//IssuedAt = DateTime.Now, // 預設值就是 DateTime.Now
Subject = userClaimsIdentity,
Expires = DateTime.Now.AddMinutes(expireMinutes),
SigningCredentials = signingCredentials
};
// 產出所需要的 JWT securityToken 物件,並取得序列化後的 Token 結果(字串格式)
var tokenHandler = new JwtSecurityTokenHandler();
var securityToken = tokenHandler.CreateToken(tokenDescriptor);
var serializeToken = tokenHandler.WriteToken(securityToken);
return serializeToken;
}
}
}
3.在appsettings.json中添加字符串
字符串如下
"JwtSettings": {
"Issuer": "MyJwtDemo",
"SignKey": "qwertyuiop123asdfgh"
}
4.在Startup.cs中注入新建的类,并配置文件
//注入JWT
services.AddSingleton<JwtHelpers>();
//验证
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
// 當驗證失敗時,回應標頭會包含 WWW-Authenticate 標頭,這裡會顯示失敗的詳細錯誤原因
options.IncludeErrorDetails = true; // 預設值為 true,有時會特別關閉
options.TokenValidationParameters = new TokenValidationParameters
{
// 透過這項宣告,就可以從 "sub" 取值並設定給 User.Identity.Name
NameClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
// 透過這項宣告,就可以從 "roles" 取值,並可讓 [Authorize] 判斷角色
RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role",
// 一般我們都會驗證 Issuer
ValidateIssuer = true,
ValidIssuer = Configuration.GetValue<string>("JwtSettings:Issuer"),
// 通常不太需要驗證 Audience
ValidateAudience = false,
//ValidAudience = "JwtAuthDemo", // 不驗證就不需要填寫
// 一般我們都會驗證 Token 的有效期間
ValidateLifetime = true,
// 如果 Token 中包含 key 才需要驗證,一般都只有簽章而已
ValidateIssuerSigningKey = false,
// "1234567890123456" 應該從 IConfiguration 取得
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration.GetValue<string>("JwtSettings:SignKey")))
};
});
5.接下来就可以在控制器中的登陆方法里创建JWT字符串了,方法如下
private readonly JwtHelpers _jwtHelpers;
public LoadController(JwtHelpers jwtHelpers)
{
_jwtHelpers = jwtHelpers;
}
//如果我们在控制器类上加了[Authorize]验证创建Token字符串的方法就一定要加上[AllowAnonymous],否则,将无法生成Token字符串
[AllowAnonymous]
[HttpPost,Route("login")]
public IActionResult Login(LoginViewModel login)
{
if (ValidateUser(login))
{
var token = _jwtHelpers.GenerateToken(login.UsersName);
HttpContext.Response.Headers.Add("token", token);
return Ok();
}
else
{
//失败的请求 状态码400
return BadRequest();
}
}
/// <summary>
/// 登录
/// </summary>
/// <param name="login"></param>
/// <returns></returns>
[HttpGet]
public bool ValidateUser(LoginViewModel login)
{
return true;
}
5.验证Token字符串
生成字符串的目的就是为了验证,怎么在Swagger里开启认证呢在Startup.cs文件中services.AddSwaggerGen方法下,复制以下代码
开启Swagger认证
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
{
Description = "在下框中输入请求头中需要添加Jwt授权Token:Bearer Token",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
BearerFormat = "JWT",
Scheme = "Bearer"
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference {
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
new string[] { }
}
});
6.以下是获取荷载信息,用户名,和用户ID的三种方法
[HttpGet("~/claims")]
public IActionResult GetClaims()
{
return Ok(User.Claims.Select(p => new { p.Type, p.Value }));
}
[HttpGet("~/username")]
public IActionResult GetUserName()
{
return Ok(User.Identity.Name);
}
[HttpGet("~/jwtid")]
public IActionResult GetUniqueId()
{
var jti = User.Claims.FirstOrDefault(p => p.Type == "jti");
return Ok(jti.Value);
}
浙公网安备 33010602011771号