最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot整合JWT實(shí)現(xiàn)Token認(rèn)證與自動刷新

 更新時(shí)間:2026年07月20日 08:42:05   作者:張老師技術(shù)棧  
還在為分布式環(huán)境下的Session共享頭疼嗎?本文帶你徹底搞懂JWT(JSON Web Token)方案,從結(jié)構(gòu)解析到工具類封裝,覆蓋登錄、刷新、攔截器校驗(yàn)和前端調(diào)用全流程,最后還總結(jié)了安全注意事項(xiàng),一篇文章讓你輕松實(shí)現(xiàn)無狀態(tài)認(rèn)證,告別Session煩惱,需要的朋友可以參考下

Session 方式在分布式環(huán)境下不好用,JWT(JSON Web Token)是目前主流的無狀態(tài)認(rèn)證方案。服務(wù)端不需要存 Session,Token 中包含了用戶信息。

一、JWT 結(jié)構(gòu)

header.payload.signature

header: 加密算法
payload: 用戶數(shù)據(jù)(不要放密碼)
signature: 簽名,防止篡改

二、JWT 工具類

@Component
public class JwtUtil {

    @Value("${jwt.secret:mySecretKey}")
    private String secret;

    @Value("${jwt.expire:86400000}")
    private long expire;  // 默認(rèn)24小時(shí)

    public String generateToken(Long userId, String username) {
        Date now = new Date();
        return Jwts.builder()
            .setSubject(userId.toString())
            .claim("username", username)
            .setIssuedAt(now)
            .setExpiration(new Date(now.getTime() + expire))
            .signWith(SignatureAlgorithm.HS256, secret)
            .compact();
    }

    public Claims parseToken(String token) {
        return Jwts.parser()
            .setSigningKey(secret)
            .parseClaimsJws(token)
            .getBody();
    }

    public boolean validateToken(String token) {
        try {
            parseToken(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}

三、登錄接口

@RestController
@RequestMapping("/auth")
public class AuthController {

    @Autowired
    private JwtUtil jwtUtil;

    @PostMapping("/login")
    public ResultVO<Map<String, Object>> login(
            @RequestParam String username,
            @RequestParam String password) {
        // 校驗(yàn)用戶名密碼
        if (!"admin".equals(username) || !"123456".equals(password)) {
            return ResultVO.error(401, "用戶名或密碼錯誤");
        }

        // 生成 Token
        String accessToken = jwtUtil.generateToken(1001L, username);
        String refreshToken = jwtUtil.generateRefreshToken(1001L);

        Map<String, Object> result = new HashMap<>();
        result.put("accessToken", accessToken);
        result.put("refreshToken", refreshToken);
        result.put("expiresIn", 86400);

        return ResultVO.success(result);
    }
}

四、Token 刷新

@PostMapping("/refresh")
public ResultVO<Map<String, Object>> refresh(
        @RequestParam String refreshToken) {
    if (!jwtUtil.validateToken(refreshToken)) {
        return ResultVO.error(401, "RefreshToken 無效");
    }

    Claims claims = jwtUtil.parseToken(refreshToken);
    Long userId = Long.parseLong(claims.getSubject());
    String username = claims.get("username", String.class);

    String newAccessToken = jwtUtil.generateToken(userId, username);
    String newRefreshToken = jwtUtil.generateRefreshToken(userId);

    return ResultVO.success(Map.of(
        "accessToken", newAccessToken,
        "refreshToken", newRefreshToken
    ));
}

五、攔截器校驗(yàn)

@Component
public class JwtInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtUtil jwtUtil;

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        String token = request.getHeader("Authorization");
        if (token == null || !token.startsWith("Bearer ")) {
            throw new BusinessException(401, "未登錄");
        }

        token = token.substring(7);
        if (!jwtUtil.validateToken(token)) {
            throw new BusinessException(401, "Token 已過期");
        }

        // 將用戶信息存入請求上下文
        Claims claims = jwtUtil.parseToken(token);
        request.setAttribute("userId", claims.getSubject());
        request.setAttribute("username", claims.get("username"));

        return true;
    }
}

六、前端調(diào)用

// 登錄
const resp = await fetch('/auth/login', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({username: 'admin', password: '123456'})
});
const { accessToken, refreshToken } = await resp.json();

// 后續(xù)請求攜帶 Token
fetch('/api/user', {
    headers: {'Authorization': 'Bearer ' + accessToken}
});

// Token 過期時(shí)用 refreshToken 刷新
async function refreshAccessToken() {
    const resp = await fetch('/auth/refresh', {
        method: 'POST',
        body: new URLSearchParams({refreshToken})
    });
    const data = await resp.json();
    accessToken = data.accessToken;
}

七、安全注意事項(xiàng)

// 1. JWT 中不要放敏感信息
Claims claims = Jwts.parser()
    .setSigningKey(secret)
    .parseClaimsJws(token)
    .getBody();
String password = claims.get("password");  // ? 錯誤!

// 2. 密鑰不要寫死,用配置中心或環(huán)境變量
@Value("${jwt.secret}")
private String secret;

// 3. accessToken 有效期短(15-30分鐘)
// refreshToken 有效期長(7天),專門用來刷新 accessToken

總結(jié)

Session 認(rèn)證:服務(wù)端存 Session,分布式下需要共享 Session
JWT 認(rèn)證: 無狀態(tài),Token 攜帶用戶信息,適合分布式

JWT 缺點(diǎn):簽發(fā)后無法主動失效(只能等過期)
解決方案:accessToken 短時(shí)效 + refreshToken 刷新機(jī)制

到此這篇關(guān)于SpringBoot整合JWT實(shí)現(xiàn)Token認(rèn)證與自動刷新的文章就介紹到這了,更多相關(guān)SpringBoot Token認(rèn)證與自動刷新內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

无锡市| 清水河县| 资兴市| 临城县| 鲁甸县| 青河县| 汕头市| 平安县| 姜堰市| 师宗县| 东港市| 屯昌县| 宜川县| 泸州市| 房山区| 沈阳市| 即墨市| 长寿区| 板桥市| 青岛市| 汤阴县| 洪江市| 龙川县| 筠连县| 马关县| 浪卡子县| 应用必备| 育儿| 镇赉县| 枣阳市| 大渡口区| 吴忠市| 噶尔县| 措勤县| 德昌县| 玉林市| 陆川县| 安义县| 鄂托克旗| 迁安市| 芷江|