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;
        }
    }
}
相关推荐
星幻元宇VR9 小时前
公共安全实训展厅设备【人防知识学习系统】
科技·学习·安全
心中有国也有家12 小时前
AtomGit Flutter 鸿蒙客户端:情绪日记的时间线实现
学习·flutter·华为·harmonyos
百里香酚兰13 小时前
【python学习笔记】pyttsx3库疑似只播报一次语音
笔记·python·学习
恣逍信点13 小时前
《凌微经》助读:本体论根基——“无之自悖”与“形性一体”
人工智能·科技·学习·程序人生·生活·交友·哲学
chh56315 小时前
C++--string
java·开发语言·网络·c++·学习
chnyi6_ya16 小时前
论文阅读笔记:VideoWeaver — 面向智能体长视频生成的技能评估与进化
论文阅读·笔记·音视频
J_yyy16 小时前
基于Reactor的文件管理服务开发笔记
c++·笔记·reactor·多线程编程·muduo
浩瀚地学16 小时前
【Java基础复习】IO流(四)
java·开发语言·经验分享·笔记·学习
疯狂打码的少年16 小时前
【操作系统】板块总结 + 下期预告(软件工程)
笔记·软件工程
心中有国也有家17 小时前
AtomGit Flutter 鸿蒙客户端:一键记录情绪的极致体验
学习·flutter·华为·harmonyos