用户校验
This commit is contained in:
15
Dockerfile.buildagent
Normal file
15
Dockerfile.buildagent
Normal 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
37
Jenkinsfile
vendored
@ -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
21
pom.xml
@ -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 -->
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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());
|
||||
|
||||
84
src/main/java/com/sczx/gateway/util/JwtUtil.java
Normal file
84
src/main/java/com/sczx/gateway/util/JwtUtil.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
70
src/main/java/com/sczx/gateway/util/RedisUtil.java
Normal file
70
src/main/java/com/sczx/gateway/util/RedisUtil.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user