一次學(xué)會JWT之Java登錄、驗證與權(quán)限控制完整流程
1. JWT 基礎(chǔ)概念
1.1 什么是 JWT?
JWT(JSON Web Token)是一種基于 JSON 的輕量級認(rèn)證方式,用于在各方之間安全地傳遞信息。它常用于 前后端分離項目的登錄認(rèn)證,替代傳統(tǒng)的 Session 機(jī)制。
特點:數(shù)據(jù)量小,傳輸快(輕量)、本身攜帶用戶信息,不依賴服務(wù)端存儲(自包含)、簽名保證數(shù)據(jù)完整性與可信度(簽名防篡改)。
1.2 為什么要用 JWT?
傳統(tǒng)的登錄認(rèn)證方式使用 Session 保存用戶信息,但在 前后端分離 項目中:
Session 需要服務(wù)端存儲,會增加服務(wù)器壓力
多臺服務(wù)器要共享 Session,需要引入 Redis
移動端、小程序調(diào)用不方便
而 JWT(JSON Web Token):
無需服務(wù)端保存狀態(tài),無狀態(tài)認(rèn)證
Token 自包含用戶信息
輕量、安全、跨平臺
1.3 JWT 的結(jié)構(gòu)
JWT 一般由三部分組成,用 . 分隔:
Header.Payload.Signature
Header(頭部)
聲明簽名算法和類型,例如:
{
"alg": "HS256",
"typ": "JWT"
}
alg: 使用的簽名算法,如 HS256(HMAC SHA-256)、RS256(RSA SHA-256)等。
typ: 類型,固定為 JWT。
Payload(載荷)
存放實際信息(Claims),分為:
Registered claims(注冊字段):如
iss(簽發(fā)者)、exp(過期時間)等Public claims(公共字段):自定義但公開的字段
Private claims(私有字段):自定義且內(nèi)部使用
常用的字段(大家約定俗稱的字段,表示一些通用的信息)
| 字段 | 含義 | 示例 |
|---|---|---|
sub | 用戶唯一標(biāo)識(Subject) | "sub": "user_10086" |
exp | 過期時間(Expiration) | "exp": 1723545600(時間戳) |
iat | 簽發(fā)時間(Issued At) | "iat": 1723459200 |
iss | 簽發(fā)者(Issuer) | "iss": "myapp.com" |
? 提醒:exp 最常用,用來控制 token 的有效期。
{
"sub": "user123",
"exp": 1723545600,
"iss": "Yq",
"iat": 1723459200,
}
自定義信息(這部分是你自己決定要告訴別人的信息)
{
"name": "Yang",
"role": "管理員",
"email": "YangQ@example.com"
}?? 注意:Payload 是 Base64 編碼的,不是加密的! 所以不要在其中存放敏感信息(如密碼)。
Signature(簽名)
用密鑰和前兩部分生成的簽名,防止數(shù)據(jù)被篡改。如(使用HMAC SHA256):
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
2. JWT 的工作流程
用戶登錄 → 服務(wù)器驗證身份
服務(wù)器生成 JWT 并返回給客戶端
客戶端每次請求都帶上 JWT(通常放在 HTTP Header 中
Authorization: Bearer <token>)服務(wù)器驗證 JWT 的合法性 → 允許訪問資源
優(yōu)點:無狀態(tài)、輕量、跨域支持
缺點:無法輕易撤銷(需維護(hù)黑名單)
3. Java中操作JWT
Java 生態(tài)中最流行的 JWT 庫是 jjwt,由 Apache 提供,簡單易用。
3.1 我們先創(chuàng)建 Spring Boot 項目并引入依賴
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
</dependencies>
3.2 再封裝一個JwtUtil工具類,用于生成和驗證 Token。
package com.yg.jwt.util;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import java.security.Key;
import java.util.Date;
public class JwtUtil {
// 建議從配置文件讀取
private static final Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
private static final long EXPIRATION = 60 * 1000; // 1分鐘
// 生成 Token
public static String generateToken(String username, String role) {
return Jwts.builder()
.setSubject(username)
.claim("role", role)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION))
.signWith(key)
.compact();
}
// 解析 Token
public static Claims parseToken(String token) {
return Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token)
.getBody();
}
}
3.3 實現(xiàn)登錄接口
package com.yg.jwt.controller;
import org.springframework.web.bind.annotation.*;
import com.yg.jwt.util.JwtUtil;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/auth")
public class AuthController {
@PostMapping("/login")
public Map<String, Object> login(@RequestParam String username, @RequestParam String password) {
Map<String, Object> result = new HashMap<>();
// 模擬賬號密碼驗證
if ("admin".equals(username) && "123456".equals(password)) {
String token = JwtUtil.generateToken(username, "admin");
result.put("code", 200);
result.put("message", "登錄成功");
result.put("token", token);
} else {
result.put("code", 401);
result.put("message", "用戶名或密碼錯誤");
}
return result;
}
}
3.4 創(chuàng)建一個攔截器(JwtInterceptor.java)
攔截請求,用來驗證 Token 是否有效。
package com.yg.jwt.interceptor;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import com.yg.jwt.util.JwtUtil;
@Component
public class JwtInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String token = authHeader.substring(7);
try {
Claims claims = JwtUtil.parseToken(token);
request.setAttribute("username", claims.getSubject());
request.setAttribute("role", claims.get("role"));
return true;
} catch (ExpiredJwtException e) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("Token 已過期");
return false;
} catch (Exception e) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("無效 Token");
return false;
}
}
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("缺少 Token");
return false;
}
}
3.5 配置攔截器
package com.yg.jwt.config;
import com.yg.jwt.interceptor.JwtInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private JwtInterceptor jwtInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/auth/login"); // 登錄接口放行
}
}?? 小插曲:為什么要配置攔截器?
因為MVC 框架需要知道“有哪些攔截器要工作”(注冊機(jī)制)、統(tǒng)一處理(避免在每個 Controller 里重復(fù)寫驗證邏輯)、全局控制(可以精確控制攔截哪些路徑、放行哪些路徑)、流程集成(攔截器是 MVC 生命周期的一部分,必須接入流程)
3.6 編寫受保護(hù)接口
package com.yg.jwt.controller;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/info")
public String getUserInfo(@RequestAttribute("username") String username,
@RequestAttribute("role") String role) {
return "當(dāng)前用戶:" + username + ",角色:" + role;
}
}
3.7 項目結(jié)構(gòu)圖
jwt │── pom.xml # Maven 依賴 │── src │ ├── main │ │ ├── java │ │ │ └── com.yq.jwt │ │ │ ├── config │ │ │ │ └── WebConfig.java # 配置攔截器 │ │ │ ├── controller │ │ │ │ ├── AuthController.java # 登錄接口 │ │ │ │ └── UserController.java # 受保護(hù)接口 │ │ │ ├── interceptor │ │ │ │ └── JwtInterceptor.java # JWT 攔截器 │ │ │ └── util │ │ │ └── JwtUtil.java # JWT 工具類 │ │ └── resources │ │ └── application.yml # 配置文件 │ └── test │ └── java # 測試代碼
4. 測試流程
本篇章用的測試工具為Apifox,使用其他測試工具也是可以的(如:Postman)。
4.1 登錄獲取 Token
POST http://localhost:8080/auth/login 參數(shù): username=admin password=123456
返回:

4.2 訪問受保護(hù)接口
GET http://localhost:8080/user/info Header: Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...
把剛剛從后端返回回來的token放到Headers里面,接著訪問后端請求數(shù)據(jù)

5. 總結(jié)
JWT 是一種輕量、跨域、無狀態(tài)的認(rèn)證方式,非常適合現(xiàn)代 Web 和微服務(wù)架構(gòu)。通過 Java 的 jjwt 庫,我們可以快速生成、解析和驗證 JWT,實現(xiàn)安全的身份驗證機(jī)制。
到此這篇關(guān)于一次學(xué)會JWT之Java登錄、驗證與權(quán)限控制完整流程的文章就介紹到這了,更多相關(guān)Java登錄、驗證與權(quán)限控制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解讀List?list=new?ArrayList()是怎么回事
這篇文章主要介紹了解讀List?list=new?ArrayList()是怎么回事,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06
關(guān)于@ComponentScan注解的用法及作用說明
這篇文章主要介紹了關(guān)于@ComponentScan注解的用法及作用說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-09-09
深入探討Java 中的 Object 類詳解(一切類的根基)
本文詳細(xì)介紹了Java中的Object類,作為所有類的根類,其重要性不言而喻,文章涵蓋了Object類的主要方法,如toString()、equals()、hashCode()等,本文深入探討 Object 類的作用、常用方法以及如何在實際開發(fā)中利用這些方法,感興趣的朋友一起看看吧2025-01-01
SpringLDAP目錄服務(wù)之LdapTemplate與LDAP操作方式
本文將深入探討Spring LDAP的核心概念、LdapTemplate的使用方法以及如何執(zhí)行常見的LDAP操作,幫助開發(fā)者有效地將LDAP集成到Spring應(yīng)用中,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-04-04
JSON字符串轉(zhuǎn)成java的Map對象詳細(xì)步驟
這篇文章主要介紹了如何將JSON字符串轉(zhuǎn)換為Java對象的步驟,包括定義Element類、使用Jackson庫解析JSON和添加依賴,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-01-01
IDEA+Maven創(chuàng)建Spring項目的實現(xiàn)步驟
這篇文章主要介紹了IDEA+Maven創(chuàng)建Spring項目的實現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07

