ASP.NET Core 簡單整合簽發 JWT (JSON Web Tokens)

sims發表於2022-03-12

什麼是 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
        });
    }
}

相關文章