Initial commit
This commit is contained in:
174
后端架构设计/11-通用基础设施-part2-JWT与拦截器.md
Normal file
174
后端架构设计/11-通用基础设施-part2-JWT与拦截器.md
Normal file
@@ -0,0 +1,174 @@
|
||||
# 通用基础设施开发文档 - Part 2(JWT + UserContext + 拦截器)
|
||||
|
||||
---
|
||||
|
||||
## 一、JwtUtil.java
|
||||
|
||||
```java
|
||||
package com.openclaw.util;
|
||||
|
||||
import io.jsonwebtoken.*;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import java.security.Key;
|
||||
import java.util.Date;
|
||||
|
||||
@Component
|
||||
public class JwtUtil {
|
||||
|
||||
private final Key key;
|
||||
private final long expireMs;
|
||||
|
||||
public JwtUtil(
|
||||
@Value("${jwt.secret}") String secret,
|
||||
@Value("${jwt.expire-ms}") long expireMs) {
|
||||
this.key = Keys.hmacShaKeyFor(secret.getBytes());
|
||||
this.expireMs = expireMs;
|
||||
}
|
||||
|
||||
public String generate(Long userId, String role) {
|
||||
return Jwts.builder()
|
||||
.setSubject(userId.toString())
|
||||
.claim("role", role)
|
||||
.setIssuedAt(new Date())
|
||||
.setExpiration(new Date(System.currentTimeMillis() + expireMs))
|
||||
.signWith(key, SignatureAlgorithm.HS256)
|
||||
.compact();
|
||||
}
|
||||
|
||||
public Claims parse(String token) {
|
||||
return Jwts.parserBuilder()
|
||||
.setSigningKey(key).build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
}
|
||||
|
||||
public Long getUserId(String token) {
|
||||
return Long.parseLong(parse(token).getSubject());
|
||||
}
|
||||
|
||||
public String getRole(String token) {
|
||||
return parse(token).get("role", String.class);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```yaml
|
||||
# application.yml
|
||||
jwt:
|
||||
secret: change-this-to-a-256-bit-random-secret-in-prod
|
||||
expire-ms: 86400000 # 24 小时
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、UserContext.java
|
||||
|
||||
```java
|
||||
package com.openclaw.util;
|
||||
|
||||
public class UserContext {
|
||||
|
||||
private static final ThreadLocal<Long> USER_ID = new ThreadLocal<>();
|
||||
private static final ThreadLocal<String> ROLE = new ThreadLocal<>();
|
||||
|
||||
public static void set(Long userId, String role) {
|
||||
USER_ID.set(userId);
|
||||
ROLE.set(role);
|
||||
}
|
||||
|
||||
public static Long getUserId() { return USER_ID.get(); }
|
||||
public static String getRole() { return ROLE.get(); }
|
||||
|
||||
public static void clear() {
|
||||
USER_ID.remove();
|
||||
ROLE.remove();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、AuthInterceptor.java
|
||||
|
||||
```java
|
||||
package com.openclaw.interceptor;
|
||||
|
||||
import com.openclaw.constant.ErrorCode;
|
||||
import com.openclaw.exception.BusinessException;
|
||||
import com.openclaw.util.JwtUtil;
|
||||
import com.openclaw.util.UserContext;
|
||||
import jakarta.servlet.http.*;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class AuthInterceptor implements HandlerInterceptor {
|
||||
|
||||
private final JwtUtil jwtUtil;
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest req,
|
||||
HttpServletResponse res,
|
||||
Object handler) {
|
||||
String auth = req.getHeader("Authorization");
|
||||
if (auth == null || !auth.startsWith("Bearer "))
|
||||
throw new BusinessException(ErrorCode.UNAUTHORIZED);
|
||||
try {
|
||||
String token = auth.substring(7);
|
||||
Long userId = jwtUtil.getUserId(token);
|
||||
String role = jwtUtil.getRole(token);
|
||||
UserContext.set(userId, role);
|
||||
} catch (Exception e) {
|
||||
throw new BusinessException(ErrorCode.UNAUTHORIZED);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest req, HttpServletResponse res,
|
||||
Object handler, Exception ex) {
|
||||
UserContext.clear(); // 防止 ThreadLocal 内存泄漏
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、WebMvcConfig.java(注册拦截器)
|
||||
|
||||
```java
|
||||
package com.openclaw.config;
|
||||
|
||||
import com.openclaw.interceptor.AuthInterceptor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.*;
|
||||
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
public class WebMvcConfig implements WebMvcConfigurer {
|
||||
|
||||
private final AuthInterceptor authInterceptor;
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(authInterceptor)
|
||||
.addPathPatterns("/api/**")
|
||||
.excludePathPatterns(
|
||||
"/api/v1/users/register",
|
||||
"/api/v1/users/login",
|
||||
"/api/v1/users/sms-code",
|
||||
"/api/v1/payments/callback/**",
|
||||
"/api/v1/skills", // 公开浏览
|
||||
"/api/v1/skills/{id}" // 公开详情
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
**文档版本**:v1.0 | **创建日期**:2026-03-16
|
||||
Reference in New Issue
Block a user