Day22:JWT 完整学习笔记 + 原理 + 面试题 + 帮助类封装

一、JWT 是什么

JWT(JSON Web Token) :是一种无状态 的身份认证令牌,登录成功后后端生成一段加密字符串,前端后续请求带 Token 鉴权,不用再每次查库校验账号密码。

二、JWT 三段结构(用 . 分隔)

  1. Header 头部加密算法、令牌类型,默认 HS256 对称加密。
  2. Payload 载荷 存放用户非敏感信息 :用户 ID、账号、角色、过期时间等。禁止存密码、隐私数据
  3. Signature 签名 头部 + 载荷 + 密钥 加密生成,防止 Token 被篡改

三、JWT 认证流程

  1. 前端登录提交账号密码
  2. 后端校验账号密码正确
  3. 后端生成 JWT Token 返回前端
  4. 前端把 Token 存在本地(LocalStorage)
  5. 后续每次请求 Header 携带 Token
  6. 后端拦截器解析、验签、判断是否过期、是否合法
  7. 合法则放行接口,无 Token / 非法 / 过期直接 401

四、JWT 优缺点

优点

  1. 无状态:服务端不用存 Session,分布式、集群友好
  2. 跨域友好:适合前后端分离
  3. 自带信息:Payload 可带用户角色、ID,减少查库
  4. 扩展性强:微服务、网关鉴权通用

缺点

  1. 一旦签发,中途无法作废(只能等过期,需配合黑名单做注销)
  2. Payload Base64 解码就能看,不能存敏感数据
  3. Token 不宜过长,携带太多字段影响请求头大小

五、适用场景

  • 前后端分离项目登录认证
  • 微服务、分布式系统鉴权
  • 第三方授权登录
  • 移动端 App 登录认证

六、JWT 高频面试题(必背)

  1. JWT 由哪几部分组成?

    Header 头部、Payload 载荷、Signature 签名三部分,用点分隔。

  2. 为什么 JWT 不能存敏感信息?

    Payload 只是 Base64 编码,可直接解码查看,不是加密,不能存密码、手机号等隐私。

  3. JWT 是有状态还是无状态?

    无状态,服务端不存储 Token 信息,靠签名校验合法性,适合集群分布式。

  4. JWT 怎么防止篡改?

    后端用密钥对 Header+Payload 生成签名,篡改任意部分签名都会校验失败。

  5. JWT 过期了怎么处理?

    前端捕获 401,跳转登录;企业常用双 Token:AccessToken 短期 + RefreshToken 无感刷新。

  6. JWT 如何实现注销?

    原生无法主动作废,解决方案:

    1. 维护 Token 黑名单
    2. 缩短过期时间 + 强制重新登录
    3. 更换全局密钥批量失效
  7. 对称加密和非对称加密区别?

    1. 对称 HS256:同一密钥加解密,简单适合单体项目
    2. 非对称 RSA:私钥签发、公钥验签,适合微服务跨项目

七、实战练习:封装 JWT 帮助类(.NET 可用直接复制)

1. 安装 NuGet

复制代码
Microsoft.IdentityModel.Tokens
System.IdentityModel.Tokens.Jwt

2. 配置节点(appsettings.json)

cs 复制代码
"Jwt": {
  "Secret": "ABCDEFG123456789ABCDEFG123456789",
  "Issuer": "AdminWeb",
  "Audience": "AdminClient",
  "ExpireMinutes": 120
}

3. 封装 JwtHelper 帮助类

新建 Common/Helper/JwtHelper.cs

cs 复制代码
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.IdentityModel.Tokens;

namespace Admin.NET.Common.Helper;

public static class JwtHelper
{
    /// <summary>
    /// 生成Token
    /// </summary>
    /// <param name="userId">用户ID</param>
    /// <param name="account">账号</param>
    /// <param name="role">角色</param>
    /// <param name="secret">密钥</param>
    /// <param name="issuer">签发人</param>
    /// <param name="audience">受众</param>
    /// <param name="expireMin">过期分钟</param>
    /// <returns>Token</returns>
    public static string GenerateToken(long userId, string account, string role,
        string secret, string issuer, string audience, int expireMin)
    {
        // 1. 声明载荷
        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.NameIdentifier, userId.ToString()),
            new Claim(ClaimTypes.Name, account),
            new Claim(ClaimTypes.Role, role)
        };

        // 2. 密钥
        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

        // 3. 生成Token
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Issuer = issuer,
            Audience = audience,
            Subject = new ClaimsIdentity(claims),
            Expires = DateTime.UtcNow.AddMinutes(expireMin),
            SigningCredentials = creds
        };

        var handler = new JwtSecurityTokenHandler();
        var securityToken = handler.CreateToken(tokenDescriptor);
        return handler.WriteToken(securityToken);
    }

    /// <summary>
    /// 校验Token
    /// </summary>
    public static bool ValidateToken(string token, string secret, string issuer, string audience, out ClaimsPrincipal? claims)
    {
        claims = null;
        try
        {
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
            var validateParam = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = issuer,
                ValidAudience = audience,
                IssuerSigningKey = key,
                ClockSkew = TimeSpan.Zero
            };

            var handler = new JwtSecurityTokenHandler();
            claims = handler.ValidateToken(token, validateParam, out _);
            return true;
        }
        catch
        {
            return false;
        }
    }
}
相关推荐
是一个Bug4 小时前
Agent(智能体)应用 的入门学习路径
学习·机器学习
2301_809051144 小时前
Linux 网络编程 学习笔记
linux·网络·学习
eggcode5 小时前
【Qt学习】Linux(ARM架构)在线安装Qt6.x
linux·qt·学习·arm
鹏北海-RemHusband6 小时前
Go 语言进阶笔记 — 面向 JS/TS 前端开发者
笔记·golang
_李小白6 小时前
【android opencv学习笔记】Day 26: 滤波算法之低通滤波与图像缩放插值
android·opencv·学习
Bechamz7 小时前
大数据开发学习Day43
大数据·学习
nnsix8 小时前
Unity QFramework ResKit、UIKit 笔记
笔记
摇滚侠8 小时前
Java 零基础全套教程,反射机制,笔记 187-188
java·开发语言·笔记
【云轩】9 小时前
如何设计一台能模拟电机的电子负载:一个硬件工程师的实战笔记
笔记·嵌入式硬件