什麼是 JWT ?
從 https://jwt.io/ 可以瞭解到對 JWT 的描述:JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.
JWT 是一個開放的,RFC 7519 工業標準方法,用來在兩個部分之間表示安全宣告。
下面來看一個 JWT 的例子:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjEyMjAiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoi55So5oi3NTk4OCIsImlzcyI6IkhaRyIsImF1ZCI6IkhaRyJ9.ipS3XPIF6QFm98olSaQzdqQ5vVrIR-_ACgaBFt0AFCg
上面是一個 JWT。可以看到,整體被兩個點分為三部分,依次為 header,payload,加密部分。
header 部分:
base64 編碼,這部分可以通過 base64 解碼得到,示例中的解碼後為:
{
"alg": "HS256",
"typ": "JWT"
}
其中,alg 表示服務端加密所用的演算法,typ 表示 token 為 JWT
payload 部分代表附加的資訊,可以傳遞一些使用者資訊等,也是 base 64 編碼,示例中解析後為 :
{
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier": "1220",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name": "使用者5988",
"iss": "HZG",
"aud": "HZG"
}
都是一些宣告,可以在生成 JWT 的時候宣告。
第三部分是加密部分,也就是使用 header 中的演算法,把 header 和 payload 部分加密,用來驗證傳遞的資訊是否被修改。
如何在 ASP.NET Core 中整合 JWT?
首先我們需要考慮的是要實現什麼功能?我們這裡只是實現了簡單的 JWT 簽發功能,不做過多討論
- 生成 token
IJwtService.cs
using System.Threading.Tasks; namespace JWTSample.Jwt; /// <summary> /// Jwt 功能介面 /// </summary> public interface IJwtService { // 生成 JWT token string GetnerateJWTToken(UserDto userDto); }
JwtService.cs
using System; using System.Linq; using System.IdentityModel.Tokens.Jwt; using System.Text; using System.Security.Claims; using Microsoft.IdentityModel.Tokens; using Microsoft.Extensions.Configuration; using Microsoft.AspNetCore.Http; namespace JWTSample.Jwt; /// <summary> /// JWT 功能類 /// </summary> public class JwtService : IJwtService { // 配置 private readonly IConfiguration _configuration; public JwtService(IConfiguration configuration) { _configuration = configuration; } /// <summary> /// 生成 JWT /// </summary> /// <param name="userDto">使用者資訊</param> /// <returns></returns> public string GetnerateJWTToken(UserDto userDto) { var claims = new Claim[] { new Claim(ClaimTypes.Name, userDto.UserName), new Claim(ClaimTypes.Role, userDto.Roles), // 使用者所在的分組 new Claim("groups", userDto.Groups) }; var issuer = _configuration[JwtOptionsConst.IssuerSettingPath]; var audience = _configuration[JwtOptionsConst.AudienceSettingPath]; var security = _configuration[JwtOptionsConst.SecurityKeySettingPath]; var expires = DateTime.Now.AddHours(Convert.ToDouble(_configuration[JwtOptionsConst.ExpiresHourSettingPath])); SymmetricSecurityKey symmetricSecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(security)); var signingCredentials = new SigningCredentials(symmetricSecurityKey, SecurityAlgorithms.HmacSha256); var jwtSecurityToken = new JwtSecurityToken(claims: claims, issuer: issuer, audience: audience, expires: expires, signingCredentials: signingCredentials); var tokenHandler = new JwtSecurityTokenHandler(); return tokenHandler.WriteToken(jwtSecurityToken); } }
如何使用?我們可以直接在控制器中注入使用
using System; using System.Linq; using System.Threading.Tasks; using System.Collections.Generic; using System.Security.Claims; using System.IdentityModel.Tokens.Jwt; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.IdentityModel.Tokens; using JWTSample.Jwt; using JWTSample.Models; namespace JWTSample.Controllers; public class AuthController : Controller { private readonly IJwtService _jwtService; public AuthController(IJwtService jwtService) { _jwtService = jwtService; } [AllowAnonymous] [HttpPost] public IActionResult Login([FromBody] LoginUserInfo loginUserInfo) { if (loginUserInfo.Name == null) { return Ok(new { Message = "使用者名稱不能為空!" }); } var userDto = new UserDto() { UserId = new Random().Next(1000), UserName = loginUserInfo.Name, Groups = "技術部", Roles = "軟體工程師", Email = "123456789@qq.com", Phone = "123456789" }; var token = _jwtService.GetnerateJWTToken(userDto); return Ok(new { Token = token }); } }