用户校验

This commit is contained in:
2025-07-22 00:58:19 +08:00
parent b1ef12c800
commit db8504fb7a
8 changed files with 229 additions and 18 deletions

15
Dockerfile.buildagent Normal file
View File

@ -0,0 +1,15 @@
# 使用 JDK 8 作为构建环境
FROM openjdk:8-jdk
# 使用阿里云的 apt 镜像源Debian 11 bullseye
RUN sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list && \
sed -i 's/security.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list
# 更新包列表并安装 Maven 和 Git
RUN apt update && \
apt install -y maven git && \
mvn --version && \
git --version
# 设置工作目录
WORKDIR /home/jenkins/workspace

37
Jenkinsfile vendored
View File

@ -1,8 +1,8 @@
pipeline {
agent any
tools {
maven 'M3'
}
// tools {
// maven 'M3'
// }
environment {
APP_NAME = "sczx_gateway"
DOCKER_IMAGE = "${APP_NAME}:latest"
@ -10,34 +10,35 @@ pipeline {
}
stages {
stage('Checkout') {
steps {
echo "📦 正在拉取代码..."
git branch: 'main', url: 'http://115.190.8.52:3000/sczx_group/sczx_gateway.git'
}
}
// stage('Checkout') {
// steps {
// echo "📦 正在拉取代码..."
// git branch: 'main', url: 'http://115.190.8.52:3000/sczx_group/sczx_gateway.git'
// }
// }
stage('Check Java Version') {
steps {
sh 'java -version'
sh 'javac -version'
}
}
stage('Build with Maven') {
stage('Build with Maven in JDK 8') {
agent {
dockerfile {
filename "Dockerfile.buildagent"
}
}
steps {
echo "🛠️ 正在使用 Maven 构建..."
sh 'mvn clean package -s settings.xml -X'
sh 'mvn clean package -s settings.xml'
}
}
stage('Check Jar File') {
agent any
steps {
sh 'ls -la target/' // 确保 jar 文件存在
}
}
stage('Build Docker Image') {
agent any
steps {
echo "🐋 正在构建 Docker 镜像..."
sh """
@ -47,6 +48,7 @@ pipeline {
}
stage('Stop Old Container') {
agent any
steps {
echo "🛑 正在停止旧容器..."
sh '''
@ -59,6 +61,7 @@ pipeline {
}
stage('Run New Container') {
agent any
steps {
echo "🟢 正在运行新容器..."
sh """

21
pom.xml
View File

@ -52,6 +52,10 @@
<!-- Dependencies -->
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
</dependency>
<!-- Spring WebFlux -->
<dependency>
<groupId>org.springframework.boot</groupId>
@ -103,6 +107,23 @@
<version>1.2.83</version>
</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>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
</dependency>
</dependencies>
<!-- Build Configuration -->

View File

@ -1,7 +1,9 @@
package com.sczx.gateway.filter;
import com.sczx.gateway.util.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
@ -38,6 +40,9 @@ public class AuthGlobalFilter implements GlobalFilter, Ordered {
"/zc/**/webjars/**"
);
@Autowired
private JwtUtil jwtUtil;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
@ -52,7 +57,8 @@ public class AuthGlobalFilter implements GlobalFilter, Ordered {
if (!isAllowed) {
// 非放行路径,校验 token
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
if (token == null || !token.startsWith("Bearer ") || !jwtUtil.validateToken(token.replace("Bearer ", ""))) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);

View File

@ -21,6 +21,7 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
/**
* 全局日志过滤器用于打印请求路径、Header、Body 和响应状态码、Body。
@ -32,11 +33,18 @@ public class LoggingGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String traceId = UUID.randomUUID().toString().substring(24,36);
// 将 traceId 添加到请求头中
ServerWebExchange mutatedExchange = exchange.mutate()
.request(builder -> builder.header("X-Trace-ID", traceId))
.build();
CustomExchange decoratedExchange = new CustomExchange(exchange);
return chain.filter(decoratedExchange)
.then(Mono.fromRunnable(() -> {
log.info("🌐 Trace ID: {}", traceId);
log.info("🌐 请求路径: {}", exchange.getRequest().getPath());
log.info("📥 请求头: {}", exchange.getRequest().getHeaders());
log.info("📥 请求体: {}", decoratedExchange.getRequestBody());

View File

@ -0,0 +1,84 @@
package com.sczx.gateway.util;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
/**
* @Author: 张黎
* @Date: 2025/07/06/14:00
* @Description:
*/
@Slf4j
@Component
public class JwtUtil {
@Value("${auth.token-expiration}")
private long expiration;
private final SecretKey key;
public JwtUtil(@Value("${auth.secret-key}") String secretKey) {
this.key = Keys.hmacShaKeyFor(secretKey.getBytes());
// this.key = Keys.secretKeyFor(SignatureAlgorithm.HS512);
log.info("JWT 密钥:{}", secretKey);
}
// 支持自定义 claims 的 generateToken 方法
// public String generateToken(SimpleUserInfoDTO simpleUserInfoDTO, String subject){
// Map<String, Object> claims = Maps.newHashMap();
// claims.put("userInfo", simpleUserInfoDTO.getUserId());
// return Jwts.builder()
// .setClaims(claims) // 设置自定义 claims
// .setSubject(subject)
// .setExpiration(new Date(System.currentTimeMillis() + expiration))
// .signWith(key, SignatureAlgorithm.HS512)
// .compact();
// }
// 从 token 中提取某个字段
// public <T> T getClaim(String token, String claimKey, Class<T> clazz) {
// return Jwts.parserBuilder()
// .setSigningKey(key)
// .build()
// .parseClaimsJws(token)
// .getBody()
// .get(claimKey, clazz);
// }
//
// // 从 token 中提取某个对象类型的字段(支持复杂对象)
// public <T> T getClaimFromToken(String token, String claimKey, Class<T> targetClass) {
// return Jwts.parserBuilder()
// .setSigningKey(key)
// .build()
// .parseClaimsJws(token)
// .getBody()
// .get(claimKey, targetClass);
// }
public String extractUsername(String token) {
return Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token)
.getBody()
.getSubject();
}
public boolean validateToken(String token) {
try {
Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token);
return true;
} catch (JwtException ex) {
return false;
}
}
}

View File

@ -0,0 +1,70 @@
package com.sczx.gateway.util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* @Author: 张黎
* @Date: 2025/07/06/14:21
* @Description:
*/
@Slf4j
@Component
public class RedisUtil {
@Autowired
private StringRedisTemplate redisTemplate;
public void set(String key, String value, long timeout, TimeUnit unit) {
redisTemplate.opsForValue().set(key, value, timeout, unit);
}
public String get(String key) {
return redisTemplate.opsForValue().get(key);
}
public void delete(String key) {
redisTemplate.delete(key);
}
private static final Long DEFAULT_EXPIRE = 120L;
public boolean getRedisLock(String key, String lockName) {
log.info("获取锁 - {}", key);
return getRedisLockWithTimeout(key, lockName, 120L);
}
/**
* 获取redislock
* 加锁并设置过期时间
*
* @param key
* @param lockName
* @return
*/
public boolean getRedisLockWithTimeout(String key, String lockName, Long lockExpire) {
boolean lock = false;
if (Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, lockName))) {
redisTemplate.expire(key, lockExpire, TimeUnit.SECONDS);
return true;
}
if (redisTemplate.getExpire(key) == -1) {
//保证锁一定设置过期时间
redisTemplate.expire(key, DEFAULT_EXPIRE, TimeUnit.SECONDS);
}
log.info("未获取到锁:" + lock + ", lockName={},key={}", lockName, key);
return lock;
}
public void deleteRedisLock(String key) {
log.info("释放锁 - {}", key);
redisTemplate.delete(key);
}
}

View File

@ -43,6 +43,10 @@ management:
health:
show-details: always
auth:
secret-key: his-is-a-very-long-and-secure-secret-key-for-jwt-signing-please-dont-use-short-keys
token-expiration: 86400000 # 24小时
logging:
level:
org.springframework.cloud.gateway: DEBUG