fix: 修复网关启动找不到服务的问题,修复jwt问题,修复自动导入失败问题。
This commit is contained in:
9
.claude/settings.local.json
Normal file
9
.claude/settings.local.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(mvn clean compile:*)",
|
||||
"Bash(mvn spring-javaformat:apply)",
|
||||
"Bash(cat:*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
2
.idea/CoolRequestCommonStatePersistent.xml
generated
2
.idea/CoolRequestCommonStatePersistent.xml
generated
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CoolRequestCommonStatePersistent">
|
||||
<option name="searchCache" value="AIOJAdminA" />
|
||||
<option name="searchCache" value="G" />
|
||||
</component>
|
||||
</project>
|
||||
13
.idea/dataSources.xml
generated
Normal file
13
.idea/dataSources.xml
generated
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||
<data-source source="LOCAL" name="jdbc:mysql://10.0.0.10/aioj_dev [DEBUG]" group="UserServiceApplication" uuid="07fb0260-0355-4ed0-9bd2-c20d69288289">
|
||||
<driver-ref>mysql.8</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<imported>true</imported>
|
||||
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
|
||||
<jdbc-url>jdbc:mysql://10.0.0.10/aioj_dev</jdbc-url>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/db-forest-config.xml
generated
Normal file
6
.idea/db-forest-config.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="db-tree-configuration">
|
||||
<option name="data" value="1:0:UserServiceApplication ---------------------------------------- 2:1:07fb0260-0355-4ed0-9bd2-c20d69288289 " />
|
||||
</component>
|
||||
</project>
|
||||
251
CLAUDE.md
251
CLAUDE.md
@@ -2,195 +2,122 @@
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
## Codebase Overview
|
||||
|
||||
This is a microservices-based Online Judge (OJ) system with AI integration called AIOJ (AI Online Judge). It's built with Spring Boot 3.5.7 and Spring Cloud 2025.0.0, following a modular Maven multi-module architecture.
|
||||
This is a microservices architecture for an Online Judge (OJ) system, built on **Spring Boot 3.5.7**. The project uses Maven as the build tool and follows a modular monorepo structure, with clearly separated core modules and service modules.
|
||||
|
||||
## Common Development Commands
|
||||
### Core Modules
|
||||
|
||||
### Building the Project
|
||||
```bash
|
||||
# Build entire project
|
||||
mvn clean install
|
||||
The `aioj-backend-common` directory contains shared components and utilities used across all service modules:
|
||||
|
||||
# Build with specific environment profile
|
||||
mvn clean install -P dev # Development (default)
|
||||
mvn clean install -P test # Testing
|
||||
mvn clean install -P prod # Production
|
||||
1. **aioj-backend-common-bom**
|
||||
Bill of materials for centralized dependency management. This ensures consistent versions of all external libraries across all modules.
|
||||
|
||||
# Format code according to Spring standards
|
||||
mvn spring-javaformat:apply
|
||||
2. **aioj-backend-common-core**
|
||||
Core utilities and Spring framework extensions:
|
||||
- `BannerApplicationRunner`: Custom application banner display during startup
|
||||
- `SpringContextHolder`: Spring context accessor for non-Spring-managed classes
|
||||
- `JavaTimeModule`: Jackson module for Java 8+ time API support
|
||||
- Common constants and enumerations
|
||||
- Application-level configurations and auto-configuration classes
|
||||
|
||||
# Build Docker images using Jib
|
||||
mvn clean package jib:build
|
||||
3. **aioj-backend-common-feign**
|
||||
Feign client configurations for seamless inter-service communication:
|
||||
- Auto-configuration for Feign clients with default settings
|
||||
- `@EnableAIOJFeignClients` annotation for enabling Feign clients with predefined base packages
|
||||
- Feign interceptors and error handling mechanisms
|
||||
|
||||
# Or use Maven wrapper
|
||||
./mvnw clean install
|
||||
```
|
||||
4. **aioj-backend-common-log**
|
||||
Aspect-oriented programming (AOP) based logging framework:
|
||||
- `SysLogAspect`: Aspect for logging system operations (controller methods, service calls)
|
||||
- `SysLogEvent` and `SysLogListener`: Event-driven logging mechanism
|
||||
- `SysLogUtils`: Utility class for creating and managing log entries
|
||||
- Configuration properties for logging behavior
|
||||
|
||||
### Running Services
|
||||
Each service runs on different ports:
|
||||
- Gateway: 8085
|
||||
- Other services: configured via Nacos
|
||||
5. **aioj-backend-common-mybatis**
|
||||
MyBatis ORM framework extensions:
|
||||
- Auto-fill functionality for `createTime` and `updateTime` fields
|
||||
- Pagination interceptor implementation
|
||||
- MyBatis configuration auto-configuration classes
|
||||
|
||||
Run individual services from their respective directories:
|
||||
```bash
|
||||
cd aioj-backend-gateway
|
||||
mvn spring-boot:run
|
||||
6. **aioj-backend-common-starter**
|
||||
Auto-configuration starters for easily enabling common features in service modules.
|
||||
|
||||
# Or with specific profile
|
||||
mvn spring-boot:run -Dspring.profiles.active=dev
|
||||
```
|
||||
|
||||
### Database Setup
|
||||
1. Create databases using the provided script:
|
||||
```bash
|
||||
mysql -u root -p < db/create_db.sql
|
||||
```
|
||||
This creates three databases: `aioj_dev`, `aioj_test`, and `aioj_prod`
|
||||
### Service Modules
|
||||
|
||||
## Architecture Overview
|
||||
The service modules represent the individual microservices that make up the system:
|
||||
|
||||
### Microservices Architecture
|
||||
The system consists of seven main services:
|
||||
1. **aioj-backend-auth**
|
||||
Authentication and authorization service:
|
||||
- JWT-based authentication with `JwtAuthenticationFilter`
|
||||
- Security configuration with Spring Security
|
||||
- User login, token generation, and validation
|
||||
- Permission verification and access control
|
||||
|
||||
1. **aioj-backend-gateway** (Port 8085)
|
||||
- API Gateway using Spring Cloud Gateway
|
||||
- Routes requests to appropriate services
|
||||
- Built with WebFlux for reactive programming
|
||||
2. **aioj-backend-gateway**
|
||||
API gateway for request routing and filtering:
|
||||
- Request routing to appropriate service modules
|
||||
- Authentication token validation before forwarding requests
|
||||
- Rate limiting and request filtering mechanisms
|
||||
|
||||
2. **aioj-backend-auth**
|
||||
- OAuth2 authentication and authorization service
|
||||
- Manages user credentials and tokens
|
||||
3. **aioj-backend-judge-service**
|
||||
Code judge service (under development):
|
||||
- Will handle code submission, compilation, and execution
|
||||
- Support for multiple programming languages
|
||||
- Test case validation and result return
|
||||
|
||||
3. **aioj-backend-user-service**
|
||||
- User management and profiles
|
||||
- Handles registration, login, profile updates
|
||||
- Integrates with Redis for session management
|
||||
4. **aioj-backend-user-service**
|
||||
User management service:
|
||||
- User registration, profile management, and information retrieval
|
||||
- User role and permission assignment
|
||||
- Integration with the auth service for authentication
|
||||
|
||||
4. **aioj-backend-question-service**
|
||||
- Problem/question management
|
||||
- Handles problem storage and retrieval
|
||||
|
||||
5. **aioj-backend-judge-service**
|
||||
- Core OJ functionality for code execution
|
||||
- Supports multiple programming languages
|
||||
5. **aioj-backend-question-service**
|
||||
Question bank service (under development):
|
||||
- Will manage programming problems, test cases, and problem categories
|
||||
- Support for problem difficulty levels and tags
|
||||
- Integration with the judge service for problem submission
|
||||
|
||||
6. **aioj-backend-ai-service**
|
||||
- AI integration for enhanced features
|
||||
- Code analysis and automated feedback
|
||||
AI-related functionality service (under development):
|
||||
- Will provide AI-assisted features like problem recommendation, code analysis, etc.
|
||||
|
||||
7. **aioj-backend-upms** (User Permission Management System)
|
||||
- Role-based access control
|
||||
- Permission management
|
||||
7. **aioj-backend-upms**
|
||||
User, permission, and menu management service:
|
||||
- Low-level user and permission management
|
||||
- Menu and resource access control
|
||||
- Integration with other services for authorization
|
||||
|
||||
### Common Modules
|
||||
- **aioj-backend-common**: Shared utilities with sub-modules:
|
||||
- `core`: Core utilities and configurations
|
||||
- `log`: Custom logging implementation
|
||||
- `starter`: Auto-configuration starters
|
||||
- `mybatis`: Database access layer
|
||||
- `feign`: HTTP client for service communication
|
||||
- `bom`: Bill of Materials for dependency management
|
||||
## Commonly Used Commands
|
||||
|
||||
## Technology Stack
|
||||
|
||||
### Core Technologies
|
||||
- **Java 17**
|
||||
- **Spring Boot 3.5.7**
|
||||
- **Spring Cloud 2025.0.0**
|
||||
- **Spring Cloud Alibaba 2025.0.0.0**
|
||||
- **Maven** for build management
|
||||
|
||||
### Database & Persistence
|
||||
- **MySQL 9.4.0** as primary database
|
||||
- **MyBatis-Plus 3.5.14** for ORM
|
||||
- **Redis** for caching and session management
|
||||
|
||||
### Cloud & Infrastructure
|
||||
- **Nacos** for service discovery and configuration (server: 10.0.0.10:8848)
|
||||
- **Spring Cloud Gateway** for API routing
|
||||
- **Docker** with Jib plugin for containerization
|
||||
- **Sentinel** for circuit breaking
|
||||
|
||||
### Security
|
||||
- **Spring Security 6.5.6** with OAuth2
|
||||
- JWT token-based authentication
|
||||
- Role-based access control
|
||||
|
||||
### API Documentation
|
||||
- **Knife4j** (OpenAPI 3) integrated across services
|
||||
|
||||
## Configuration Management
|
||||
|
||||
### Environment-Specific Configuration
|
||||
Three environments are supported:
|
||||
- `dev` (development, default)
|
||||
- `test` (testing)
|
||||
- `prod` (production)
|
||||
|
||||
Configuration files:
|
||||
- `bootstrap.yml` - Nacos service discovery configuration
|
||||
- `application.yml` - Main application configuration
|
||||
- `application-{env}.yml` - Environment-specific settings
|
||||
|
||||
### Nacos Integration
|
||||
All services use Nacos for:
|
||||
- Service discovery
|
||||
- Configuration management
|
||||
- Centralized properties management
|
||||
|
||||
Default Nacos configuration:
|
||||
```yaml
|
||||
spring:
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: 10.0.0.10:8848
|
||||
username: nacos
|
||||
password: nacos
|
||||
```
|
||||
|
||||
## Database Schema
|
||||
|
||||
### Environment Databases
|
||||
- Development: `aioj_dev`
|
||||
- Testing: `aioj_test`
|
||||
- Production: `aioj_prod`
|
||||
|
||||
All databases use UTF-8 character set with `utf8mb4_general_ci` collation.
|
||||
|
||||
## Development Guidelines
|
||||
### Build
|
||||
- **Build the entire project**: `mvn clean compile`
|
||||
- **Build with tests**: `mvn clean install`
|
||||
- **Build a single module**: `mvn clean compile -pl aioj-backend-auth`
|
||||
|
||||
### Code Formatting
|
||||
- Uses Spring JavaFormat plugin for consistent code style
|
||||
- IDE plugin available: https://repo1.maven.org/maven2/io/spring/javaformat/spring-javaformat-intellij-idea-plugin
|
||||
- Run `mvn spring-javaformat:apply` before commits
|
||||
- **Format code**: `mvn spring-javaformat:apply`
|
||||
- **Check code format**: `mvn spring-javaformat:check`
|
||||
|
||||
### Docker Integration
|
||||
- Jib plugin configured for container builds
|
||||
- Target registry: `10.0.0.3/aioj/{service-name}:{version}`
|
||||
- JVM memory configured: -Xms512m -Xmx512m
|
||||
### Testing
|
||||
- **Run all tests**: `mvn test`
|
||||
- **Run tests for a single module**: `mvn test -pl aioj-backend-user-service`
|
||||
|
||||
### Service Communication
|
||||
- Uses OpenFeign for inter-service communication
|
||||
- Load balancing with Spring Cloud LoadBalancer
|
||||
- Circuit breaking with Sentinel
|
||||
### Running Services
|
||||
- **Run a service locally**: Use Spring Boot's `Application` class directly in IDE or use `mvn spring-boot:run -pl <module-name>`
|
||||
- **Example**: `mvn spring-boot:run -pl aioj-backend-auth`
|
||||
|
||||
### Logging
|
||||
- Custom logging implementation in `aioj-backend-common-log`
|
||||
- Integrates with Spring Security for context logging
|
||||
- Uses Hutool utilities for enhanced logging
|
||||
## Architecture Highlights
|
||||
|
||||
## Testing
|
||||
- Spring Boot Test framework included
|
||||
- Spring Security Test for authentication testing
|
||||
- Test structure is evolving - check individual modules for test coverage
|
||||
- **Authentication**: JWT-based authentication implemented in `aioj-backend-auth` with `JwtAuthenticationFilter`
|
||||
- **Logging**: Aspect-oriented logging with `SysLogAspect` in `aioj-backend-common-log`
|
||||
- **Database**: MyBatis with auto-fill for create/update times implemented in `common-mybatis`
|
||||
- **Inter-service communication**: Feign clients with auto-configuration from `common-feign`
|
||||
- **Banner**: Custom application banner system in `common-core`
|
||||
|
||||
## Important Notes
|
||||
## Key Entry Points
|
||||
|
||||
1. **Service Dependencies**: Services depend on Nacos for discovery - ensure Nacos is running before starting services
|
||||
2. **Database Setup**: Run the database creation script before first run
|
||||
3. **Port Configuration**: Gateway runs on 8085, other services are dynamically registered
|
||||
4. **Environment Profiles**: Default is `dev` - use appropriate profiles for different environments
|
||||
5. **Configuration Management**: Most configuration is externalized to Nacos - check Nacos for service-specific settings
|
||||
- **Gateway Application**: `aioj-backend-gateway/src/main/java/cn/meowrain/aioj/backend/gateway/AIOJGatewayApplication.java`
|
||||
- **Auth Application**: `aioj-backend-auth/src/main/java/cn/meowrain/aioj/backend/auth/AIOJAuthApplication.java`
|
||||
- **User Service Application**: `aioj-backend-user-service/src/main/java/cn/meowrain/aioj/backend/userservice/UserServiceApplication.java`
|
||||
@@ -1,5 +1,7 @@
|
||||
package cn.meowrain.aioj.backend.auth.config;
|
||||
|
||||
import cn.meowrain.aioj.backend.auth.filter.JwtAuthenticationFilter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
@@ -10,11 +12,15 @@ import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@RequiredArgsConstructor
|
||||
public class SecurityConfiguration {
|
||||
|
||||
private final JwtAuthenticationFilter jwtAuthenticationFilter;
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http.csrf(csrf -> csrf.disable())
|
||||
@@ -24,7 +30,8 @@ public class SecurityConfiguration {
|
||||
"/v3/api-docs/**", "/favicon.ico")
|
||||
.permitAll()
|
||||
.anyRequest()
|
||||
.authenticated());
|
||||
.authenticated())
|
||||
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
return http.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,106 @@
|
||||
package cn.meowrain.aioj.backend.auth.filter;
|
||||
|
||||
import cn.meowrain.aioj.backend.auth.service.AuthService;
|
||||
import cn.meowrain.aioj.backend.auth.utils.JwtUtil;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* JWT拦截器
|
||||
* JWT认证过滤器
|
||||
* 拦截所有请求,验证JWT Token
|
||||
*/
|
||||
@Component
|
||||
public class JwtAuthenticationFilter {
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
private final JwtUtil jwtUtil;
|
||||
private final AuthService authService;
|
||||
|
||||
private static final String TOKEN_PREFIX = "Bearer ";
|
||||
private static final String HEADER_NAME = "Authorization";
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
try {
|
||||
String token = extractTokenFromRequest(request);
|
||||
|
||||
if (StringUtils.hasText(token) && jwtUtil.isTokenValid(token)) {
|
||||
Claims claims = jwtUtil.parseClaims(token);
|
||||
Authentication authentication = createAuthentication(claims);
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
|
||||
log.debug("JWT Authentication successful for user: {}", claims.getSubject());
|
||||
} else {
|
||||
log.debug("No valid JWT token found in request");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("JWT Authentication failed", e);
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从请求中提取JWT Token
|
||||
*/
|
||||
private String extractTokenFromRequest(HttpServletRequest request) {
|
||||
String bearerToken = request.getHeader(HEADER_NAME);
|
||||
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(TOKEN_PREFIX)) {
|
||||
return bearerToken.substring(TOKEN_PREFIX.length());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据JWT Claims创建Authentication对象
|
||||
*/
|
||||
private Authentication createAuthentication(Claims claims) {
|
||||
String userId = claims.getSubject();
|
||||
String userName = claims.get("userName", String.class);
|
||||
String role = claims.get("role", String.class);
|
||||
|
||||
// 创建权限列表
|
||||
List<SimpleGrantedAuthority> authorities = Collections.singletonList(
|
||||
new SimpleGrantedAuthority("ROLE_" + (role != null ? role : "USER"))
|
||||
);
|
||||
|
||||
// 创建认证对象
|
||||
UsernamePasswordAuthenticationToken authentication =
|
||||
new UsernamePasswordAuthenticationToken(userId, null, authorities);
|
||||
|
||||
return authentication;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
|
||||
String path = request.getRequestURI();
|
||||
// 跳过不需要JWT验证的路径
|
||||
return path.startsWith("/v1/auth/") ||
|
||||
path.startsWith("/doc.html") ||
|
||||
path.startsWith("/swagger-ui/") ||
|
||||
path.startsWith("/swagger-resources/") ||
|
||||
path.startsWith("/webjars/") ||
|
||||
path.startsWith("/v3/api-docs/") ||
|
||||
path.equals("/favicon.ico");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,5 +63,9 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -14,7 +14,9 @@ import java.time.format.DateTimeFormatter;
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class BannerApplicationRunner implements ApplicationRunner {
|
||||
|
||||
private final Environment env;
|
||||
|
||||
@Value("${spring.application.name:unknown}")
|
||||
private String appName;
|
||||
|
||||
@@ -43,6 +45,7 @@ public class BannerApplicationRunner implements ApplicationRunner {
|
||||
|
||||
printBanner(appName, profiles, port, jvm, pid, time, gitCommit);
|
||||
}
|
||||
|
||||
private void printBanner(String appName, String profiles, String port, String jvm, String pid, String time,
|
||||
String gitCommit) {
|
||||
|
||||
@@ -53,4 +56,5 @@ public class BannerApplicationRunner implements ApplicationRunner {
|
||||
+ "------------------------------------------------------------\n";
|
||||
System.out.println(banner);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,8 +7,10 @@ import org.springframework.core.env.Environment;
|
||||
|
||||
@AutoConfiguration
|
||||
public class AIOJBannerAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public BannerApplicationRunner bannerApplicationRunner(Environment env) {
|
||||
return new BannerApplicationRunner(env);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ package cn.meowrain.aioj.backend.framework.core.constants;
|
||||
* 全局服务名称
|
||||
*/
|
||||
public class ServiceNameConstants {
|
||||
|
||||
/**
|
||||
* 用户服务 SERVICE NAME
|
||||
*/
|
||||
@@ -18,4 +19,5 @@ public class ServiceNameConstants {
|
||||
* UPMS模块
|
||||
*/
|
||||
public static final String UPMS_SERVICE = "upms-service";
|
||||
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import cn.meowrain.aioj.backend.framework.core.web.Result;
|
||||
import cn.meowrain.aioj.backend.framework.core.web.Results;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.FieldError;
|
||||
@@ -12,6 +14,8 @@ import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -19,10 +23,16 @@ import java.util.List;
|
||||
*/
|
||||
@Slf4j
|
||||
@RestControllerAdvice
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
public class GlobalExceptionHandler {
|
||||
// 加这个构造器,启动看日志
|
||||
public GlobalExceptionHandler() {
|
||||
System.out.println("===== 自定义异常处理器已加载 =====");
|
||||
}
|
||||
|
||||
/**
|
||||
* 捕获所有参数错误,然后统一捕获并且抛出
|
||||
*
|
||||
* @param request {@link HttpServletRequest}
|
||||
* @param ex {@link org.springframework.validation.method.MethodValidationException}
|
||||
* @return {@link Result<Void>}
|
||||
@@ -42,6 +52,7 @@ public class GlobalExceptionHandler {
|
||||
|
||||
/**
|
||||
* 抽象异常捕获其
|
||||
*
|
||||
* @param request {@link HttpServletRequest}
|
||||
* @param ex {@link AbstractException}
|
||||
* @return {@link Result<Void>}
|
||||
@@ -74,6 +85,7 @@ public class GlobalExceptionHandler {
|
||||
|
||||
/**
|
||||
* 获取请求URL
|
||||
*
|
||||
* @param request {@link HttpServletRequest}
|
||||
* @return String
|
||||
*/
|
||||
|
||||
@@ -10,7 +10,6 @@ import java.io.Serial;
|
||||
import java.time.*;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
|
||||
public class JavaTimeModule extends SimpleModule {
|
||||
|
||||
@Serial
|
||||
|
||||
@@ -14,9 +14,11 @@ import org.springframework.stereotype.Service;
|
||||
@Slf4j
|
||||
@Service
|
||||
public class SpringContextHolder implements ApplicationContextAware, EnvironmentAware, DisposableBean {
|
||||
|
||||
private static ApplicationContext applicationContext = null;
|
||||
|
||||
private static Environment environment = null;
|
||||
|
||||
/**
|
||||
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
|
||||
*/
|
||||
@@ -56,6 +58,7 @@ public class SpringContextHolder implements ApplicationContextAware, Environmen
|
||||
}
|
||||
applicationContext = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发布事件
|
||||
* @param event
|
||||
@@ -66,6 +69,7 @@ public class SpringContextHolder implements ApplicationContextAware, Environmen
|
||||
}
|
||||
applicationContext.publishEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是微服务
|
||||
* @return boolean
|
||||
|
||||
@@ -4,4 +4,5 @@ import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
|
||||
@AutoConfiguration
|
||||
public class FeignAutoConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@@ -9,5 +9,7 @@ import java.lang.annotation.*;
|
||||
@Documented
|
||||
@EnableFeignClients
|
||||
public @interface EnableAIOJFeignClients {
|
||||
|
||||
String[] basePackages() default {};
|
||||
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.springframework.expression.EvaluationContext;
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class SysLogAspect {
|
||||
|
||||
/**
|
||||
* 环绕通知方法,用于处理系统日志记录
|
||||
* @param point 连接点对象
|
||||
@@ -76,4 +77,5 @@ public class SysLogAspect {
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,5 +30,4 @@ public class AIOJLogPropertiesConfiguration {
|
||||
@Value("${log.exclude-fields:password,mobile,idcard,phone}")
|
||||
private List<String> excludeFields;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package cn.meowrain.aioj.backend.framework.log.event;
|
||||
|
||||
|
||||
import cn.meowrain.aioj.backend.upms.api.entity.SysLog;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ public class SysLogListener implements InitializingBean {
|
||||
objectMapper.setFilterProvider(filters);
|
||||
objectMapper.registerModule(new JavaTimeModule());
|
||||
}
|
||||
|
||||
/**
|
||||
* 属性过滤混合类:用于通过名称过滤属性
|
||||
*
|
||||
@@ -72,4 +73,5 @@ public class SysLogListener implements InitializingBean {
|
||||
class PropertyFilterMixIn {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ import java.util.Objects;
|
||||
|
||||
public final class SysLogUtils {
|
||||
|
||||
|
||||
/**
|
||||
* 获取系统日志事件源
|
||||
* @return 系统日志事件源对象
|
||||
@@ -47,7 +46,8 @@ public final class SysLogUtils {
|
||||
sysLog.setServiceId(SpringUtil.getProperty("spring.application.name"));
|
||||
|
||||
// get 参数脱敏
|
||||
AIOJLogPropertiesConfiguration logProperties = SpringContextHolder.getBean(AIOJLogPropertiesConfiguration.class);
|
||||
AIOJLogPropertiesConfiguration logProperties = SpringContextHolder
|
||||
.getBean(AIOJLogPropertiesConfiguration.class);
|
||||
Map<String, String[]> paramsMap = MapUtil.removeAny(new HashMap<>(request.getParameterMap()),
|
||||
ArrayUtil.toArray(logProperties.getExcludeFields(), String.class));
|
||||
sysLog.setParams(HttpUtil.toParams(paramsMap));
|
||||
|
||||
@@ -50,17 +50,14 @@
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-datasource-extension</artifactId>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-openapi3-jakarta-spring-boot-starter -->
|
||||
<!--
|
||||
https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-openapi3-jakarta-spring-boot-starter -->
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
|
||||
<version>4.5.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-bootstrap</artifactId>
|
||||
<version>4.3.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.meowrain</groupId>
|
||||
<artifactId>aioj-backend-common-core</artifactId>
|
||||
|
||||
@@ -19,7 +19,6 @@ import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
@@ -27,7 +26,6 @@ import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Slf4j
|
||||
@@ -44,15 +42,6 @@ public class AuthGlobalFilter implements GlobalFilter, Ordered {
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
/**
|
||||
* 不需要认证的路径
|
||||
*/
|
||||
private static final String[] DEFAULT_WHITE_LIST = {
|
||||
"/api/v1/auth/login",
|
||||
"/api/v1/auth/register",
|
||||
"/api/v1/auth/refresh",
|
||||
"/api/v1/user/info"
|
||||
};
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||
@@ -60,6 +49,7 @@ public class AuthGlobalFilter implements GlobalFilter, Ordered {
|
||||
String path = request.getURI().getPath();
|
||||
|
||||
log.info("Auth filter processing request: {}", path);
|
||||
log.info("Loaded white list from config: {}", gatewayPropertiesConfiguration.getWhiteList());
|
||||
|
||||
// 检查是否在白名单中
|
||||
if (isWhiteListPath(path)) {
|
||||
@@ -97,13 +87,6 @@ public class AuthGlobalFilter implements GlobalFilter, Ordered {
|
||||
* 检查路径是否在白名单中
|
||||
*/
|
||||
private boolean isWhiteListPath(String path) {
|
||||
// 先检查默认白名单
|
||||
for (String whitePath : DEFAULT_WHITE_LIST) {
|
||||
if (antPathMatcher.match(whitePath, path)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查配置文件中的白名单
|
||||
if (gatewayPropertiesConfiguration.getWhiteList() != null && !gatewayPropertiesConfiguration.getWhiteList().isEmpty()) {
|
||||
for (String whitePath : gatewayPropertiesConfiguration.getWhiteList()) {
|
||||
@@ -122,7 +105,7 @@ public class AuthGlobalFilter implements GlobalFilter, Ordered {
|
||||
private Mono<Boolean> validateToken(String token) {
|
||||
return webClientBuilder.build()
|
||||
.post()
|
||||
.uri("lb://auth-service/api/v1/auth/validate")
|
||||
.uri("lb://auth-service/v1/auth/validate")
|
||||
.header(HttpHeaders.AUTHORIZATION, "Bearer " + token)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.retrieve()
|
||||
|
||||
@@ -8,11 +8,59 @@ spring:
|
||||
nacos:
|
||||
discovery:
|
||||
enabled: true
|
||||
register-enabled: true
|
||||
register-enabled: false
|
||||
server-addr: 10.0.0.10:8848
|
||||
username: nacos
|
||||
password: nacos
|
||||
config:
|
||||
enabled: false
|
||||
import-check:
|
||||
enabled: false
|
||||
gateway:
|
||||
# Gateway 发现定位器配置
|
||||
server:
|
||||
webflux:
|
||||
discovery:
|
||||
locator:
|
||||
enabled: true
|
||||
lower-case-service-id: true
|
||||
loadbalancer:
|
||||
nacos:
|
||||
enabled: true
|
||||
retry:
|
||||
enabled: true
|
||||
max-retries-on-same-service-instance: 1
|
||||
max-retries-on-next-service-instance: 2
|
||||
cache:
|
||||
enabled: true
|
||||
ttl: 35s
|
||||
health-check:
|
||||
initial-delay: 0ms
|
||||
interval: 30s
|
||||
|
||||
|
||||
aioj-backend-gateway:
|
||||
# 白名单配置
|
||||
white-list:
|
||||
- /api/v1/auth/login
|
||||
- /api/v1/auth/register
|
||||
- /api/v1/auth/refresh
|
||||
- /api/v1/user/register
|
||||
- /api/v1/user/info
|
||||
- /api/v1/question/list
|
||||
- /api/v1/question/detail/**
|
||||
- /actuator/health
|
||||
- /swagger-ui/**
|
||||
|
||||
logging:
|
||||
level:
|
||||
root: INFO
|
||||
# Nacos 相关日志
|
||||
com.alibaba.nacos: INFO
|
||||
com.alibaba.cloud.nacos: DEBUG
|
||||
# LoadBalancer 日志
|
||||
org.springframework.cloud.loadbalancer: DEBUG
|
||||
# Gateway 日志
|
||||
org.springframework.cloud.gateway: DEBUG
|
||||
# 自定义过滤器日志
|
||||
cn.meowrain.aioj.backend.gateway: DEBUG
|
||||
|
||||
@@ -1,29 +1,50 @@
|
||||
server:
|
||||
port: 8085
|
||||
error:
|
||||
include-stacktrace: never
|
||||
|
||||
spring:
|
||||
profiles:
|
||||
active: @env@
|
||||
cloud:
|
||||
gateway:
|
||||
server:
|
||||
webflux:
|
||||
routes:
|
||||
- id: auth-service
|
||||
uri: lb://auth-service/api
|
||||
uri: lb://auth-service
|
||||
predicates:
|
||||
- Path=/api/v1/auth/**
|
||||
filters:
|
||||
- name: Retry
|
||||
args:
|
||||
retries: 3
|
||||
statuses: BAD_GATEWAY,SERVICE_UNAVAILABLE
|
||||
backoff:
|
||||
firstBackoff: 50ms
|
||||
maxBackoff: 500ms
|
||||
- id: user-service
|
||||
uri: lb://user-service/api
|
||||
uri: lb://user-service
|
||||
predicates:
|
||||
- Path=/api/v1/user/**
|
||||
filters:
|
||||
- name: Retry
|
||||
args:
|
||||
retries: 3
|
||||
statuses: BAD_GATEWAY,SERVICE_UNAVAILABLE
|
||||
backoff:
|
||||
firstBackoff: 50ms
|
||||
maxBackoff: 500ms
|
||||
# 设置应用启动后的就绪探针
|
||||
lifecycle:
|
||||
timeout-per-shutdown-phase: 30s
|
||||
|
||||
aioj-backend-gateway:
|
||||
# 白名单配置
|
||||
white-list:
|
||||
- /api/v1/auth/login
|
||||
- /api/v1/auth/register
|
||||
- /api/v1/user/register
|
||||
- /api/v1/auth/refresh
|
||||
- /api/v1/user/info
|
||||
- /api/v1/question/list
|
||||
- /api/v1/question/detail/**
|
||||
- /actuator/health
|
||||
- /swagger-ui/**
|
||||
- /v3/api-docs/**
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
spring:
|
||||
application:
|
||||
name: aioj-gateway
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: 10.0.0.10:8848
|
||||
username: nacos
|
||||
password: nacos
|
||||
config:
|
||||
server-addr: 10.0.0.10:8848
|
||||
username: nacos
|
||||
password: nacos
|
||||
file-extension: yaml
|
||||
group: DEFAULT_GROUP
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
package cn.meowrain.aioj.backend.upms.api.entity;
|
||||
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
@FeignClient(contextId = "remoteLogService", value = ServiceNameConstants.UPMS_SERVICE)
|
||||
public interface RemoteLogService {
|
||||
|
||||
/**
|
||||
* 保存日志 (异步多线程调用,无token)
|
||||
* @param sysLog 日志实体
|
||||
@@ -18,4 +19,5 @@ public interface RemoteLogService {
|
||||
@NoToken
|
||||
@PostMapping("/log/save")
|
||||
Result<Boolean> saveLog(@RequestBody SysLog sysLog);
|
||||
|
||||
}
|
||||
|
||||
@@ -20,7 +20,12 @@
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.meowrain</groupId>
|
||||
<artifactId>aioj-backend-common-starter</artifactId>
|
||||
<artifactId>aioj-backend-common-core</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.meowrain</groupId>
|
||||
<artifactId>aioj-backend-common-log</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -60,21 +65,15 @@
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<scope>runtime</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.springframework.boot</groupId>-->
|
||||
<!-- <artifactId>spring-boot-devtools</artifactId>-->
|
||||
<!-- <scope>runtime</scope>-->
|
||||
<!-- <optional>true</optional>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.meowrain</groupId>
|
||||
<artifactId>aioj-backend-common-core</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -5,7 +5,8 @@ import org.springframework.context.annotation.ComponentScans;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@ComponentScans({ @ComponentScan("cn.meowrain.aioj.backend.framework.core.banner") })
|
||||
// @ComponentScans({
|
||||
// @ComponentScan("cn.meowrain.aioj.backend.framework.core.banner") })
|
||||
public class FrameworkConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ server:
|
||||
port: 10010
|
||||
servlet:
|
||||
context-path: /api
|
||||
error:
|
||||
include-stacktrace: never
|
||||
springdoc:
|
||||
api-docs:
|
||||
enabled: true
|
||||
|
||||
243
docs/auth-api.md
Normal file
243
docs/auth-api.md
Normal file
@@ -0,0 +1,243 @@
|
||||
# AIOJ 认证服务 API 文档
|
||||
|
||||
## 概述
|
||||
|
||||
AIOJ认证服务提供JWT(JSON Web Token)为基础的用户认证和授权功能。该服务负责用户登录、令牌生成、令牌刷新和令牌验证。
|
||||
|
||||
**基础信息:**
|
||||
- 服务名称: auth-service
|
||||
- 基础路径: `/api`
|
||||
- API版本: v1
|
||||
- 认证方式: JWT Bearer Token
|
||||
- 数据格式: JSON
|
||||
|
||||
## JWT认证机制
|
||||
|
||||
### 访问令牌 (Access Token)
|
||||
- 有效期: 15分钟
|
||||
- 用途: 访问受保护的API接口
|
||||
- 格式: Bearer Token
|
||||
|
||||
### 刷新令牌 (Refresh Token)
|
||||
- 有效期: 7天
|
||||
- 用途: 获取新的Access Token
|
||||
- 存储位置: Redis
|
||||
|
||||
### 请求头格式
|
||||
```
|
||||
Authorization: Bearer {access_token}
|
||||
```
|
||||
|
||||
## API接口
|
||||
|
||||
### 1. 用户登录
|
||||
用户通过用户名和密码进行登录认证。
|
||||
|
||||
**接口信息:**
|
||||
- URL: `POST /api/v1/auth/login`
|
||||
- 描述: 用户登录获取访问令牌
|
||||
- 认证要求: 无需认证
|
||||
|
||||
**请求参数:**
|
||||
```json
|
||||
{
|
||||
"userAccount": "string", // 用户账号
|
||||
"userPassword": "string" // 用户密码
|
||||
}
|
||||
```
|
||||
|
||||
**请求示例:**
|
||||
```bash
|
||||
curl -X POST http://localhost:10011/api/v1/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"userAccount": "admin",
|
||||
"userPassword": "password123"
|
||||
}'
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "操作成功",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"userAccount": "admin",
|
||||
"unionId": null,
|
||||
"accessToken": "eyJhbGciOiJIUzI1NiJ9...",
|
||||
"refreshToken": "eyJhbGciOiJIUzI1NiJ9...",
|
||||
"expire": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 令牌刷新
|
||||
使用刷新令牌获取新的访问令牌。
|
||||
|
||||
**接口信息:**
|
||||
- URL: `POST /api/v1/auth/refresh`
|
||||
- 描述: 刷新访问令牌
|
||||
- 认证要求: 无需认证
|
||||
|
||||
**请求参数:**
|
||||
```
|
||||
refreshToken=string // 刷新令牌
|
||||
```
|
||||
|
||||
**请求示例:**
|
||||
```bash
|
||||
curl -X POST "http://localhost:10011/api/v1/auth/refresh?refreshToken=eyJhbGciOiJIUzI1NiJ9..."
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "操作成功",
|
||||
"data": {
|
||||
"id": null,
|
||||
"userAccount": null,
|
||||
"unionId": null,
|
||||
"accessToken": "eyJhbGciOiJIUzI1NiJ9...",
|
||||
"refreshToken": "eyJhbGciOiJIUzI1NiJ9...",
|
||||
"expire": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 获取访问令牌
|
||||
简化版的登录接口,仅返回访问令牌。
|
||||
|
||||
**接口信息:**
|
||||
- URL: `POST /api/v1/auth/auth`
|
||||
- 描述: 获取访问令牌(简化版登录)
|
||||
- 认证要求: 无需认证
|
||||
|
||||
**请求参数:**
|
||||
```json
|
||||
{
|
||||
"userAccount": "string", // 用户账号
|
||||
"userPassword": "string" // 用户密码
|
||||
}
|
||||
```
|
||||
|
||||
**请求示例:**
|
||||
```bash
|
||||
curl -X POST http://localhost:10011/api/v1/auth/auth \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"userAccount": "admin",
|
||||
"userPassword": "password123"
|
||||
}'
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "操作成功",
|
||||
"data": "eyJhbGciOiJIUzI1NiJ9..."
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 令牌验证
|
||||
验证访问令牌的有效性。
|
||||
|
||||
**接口信息:**
|
||||
- URL: `POST /api/v1/auth/validate`
|
||||
- 描述: 验证访问令牌
|
||||
- 认证要求: 可选的Authorization头
|
||||
|
||||
**请求头:**
|
||||
```
|
||||
Authorization: Bearer {access_token} // 可选
|
||||
```
|
||||
|
||||
**请求示例:**
|
||||
```bash
|
||||
curl -X POST http://localhost:10011/api/v1/auth/validate \
|
||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..."
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "操作成功",
|
||||
"data": true
|
||||
}
|
||||
```
|
||||
|
||||
## 状态码说明
|
||||
|
||||
| 状态码 | 说明 | 描述 |
|
||||
|--------|------|------|
|
||||
| 200 | OK | 请求成功 |
|
||||
| 400 | Bad Request | 请求参数错误 |
|
||||
| 401 | Unauthorized | 未授权访问或令牌无效 |
|
||||
| 403 | Forbidden | 禁止访问 |
|
||||
| 500 | Internal Server Error | 服务器内部错误 |
|
||||
|
||||
## 错误响应格式
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "错误描述",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
## 常见错误码
|
||||
|
||||
| 错误信息 | 可能原因 | 解决方案 |
|
||||
|----------|----------|----------|
|
||||
| "用户不存在或密码错误" | 用户账号或密码不正确 | 检查用户名和密码 |
|
||||
| "Refresh Token 已过期" | 刷新令牌已过期 | 重新登录获取新令牌 |
|
||||
| "Refresh Token 已失效" | 刷新令牌在Redis中不存在或已失效 | 重新登录获取新令牌 |
|
||||
| "系统错误" | 服务间调用失败或系统异常 | 检查服务状态和网络连接 |
|
||||
|
||||
## 配置信息
|
||||
|
||||
### JWT配置
|
||||
```yaml
|
||||
jwt:
|
||||
secret: "12345678901234567890123456789012" # 32字节密钥
|
||||
access-expire: 900000 # 15分钟(毫秒)
|
||||
refresh-expire: 604800000 # 7天(毫秒)
|
||||
```
|
||||
|
||||
### 服务配置
|
||||
```yaml
|
||||
spring:
|
||||
application:
|
||||
name: auth-service
|
||||
server:
|
||||
port: 10011
|
||||
servlet:
|
||||
context-path: /api
|
||||
```
|
||||
|
||||
## 安全注意事项
|
||||
|
||||
1. **令牌存储**: Access Token应存储在内存或HttpOnly Cookie中
|
||||
2. **HTTPS传输**: 生产环境必须使用HTTPS协议
|
||||
3. **密钥管理**: JWT密钥应定期轮换,使用强密钥
|
||||
4. **令牌过期**: 合理设置令牌过期时间,平衡安全性和用户体验
|
||||
5. **错误处理**: 不要在错误信息中泄露敏感信息
|
||||
|
||||
## 使用流程
|
||||
|
||||
1. **用户登录**: 调用`/login`接口获取Access Token和Refresh Token
|
||||
2. **API访问**: 在请求头中携带Access Token访问受保护接口
|
||||
3. **令牌刷新**: Access Token过期时使用Refresh Token获取新的Access Token
|
||||
4. **令牌验证**: 可使用`/validate`接口验证Token有效性
|
||||
|
||||
## 联系信息
|
||||
|
||||
如有问题或建议,请联系开发团队。
|
||||
|
||||
---
|
||||
*文档版本: v1.0*
|
||||
*更新时间: 2025-12-14*
|
||||
22
pom.xml
22
pom.xml
@@ -66,7 +66,8 @@
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<!--Spring Boot依赖-->
|
||||
<!--Spring
|
||||
Boot依赖-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
@@ -75,7 +76,8 @@
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<!-- Spring Cloud依赖-->
|
||||
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies -->
|
||||
<!--
|
||||
https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-dependencies</artifactId>
|
||||
@@ -96,10 +98,6 @@
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<includes>
|
||||
<include>application*.yml</include>
|
||||
<include>application*.properties</include>
|
||||
</includes>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
@@ -120,7 +118,8 @@
|
||||
<version>${spring-boot.version}</version>
|
||||
</plugin>
|
||||
<!--
|
||||
代码格式插件,默认使用spring 规则,可运行命令进行项目格式化:./mvnw spring-javaformat:apply 或 mvn spring-javaformat:apply,可在IDEA中安装插件以下插件进行自动格式化:
|
||||
代码格式插件,默认使用spring 规则,可运行命令进行项目格式化:./mvnw spring-javaformat:apply 或 mvn
|
||||
spring-javaformat:apply,可在IDEA中安装插件以下插件进行自动格式化:
|
||||
https://repo1.maven.org/maven2/io/spring/javaformat/spring-javaformat-intellij-idea-plugin
|
||||
-->
|
||||
<plugin>
|
||||
@@ -135,7 +134,8 @@
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!--打包jar 与git commit 关联插件-->
|
||||
<!--打包jar
|
||||
与git commit 关联插件-->
|
||||
<plugin>
|
||||
<groupId>io.github.git-commit-id</groupId>
|
||||
<artifactId>git-commit-id-maven-plugin</artifactId>
|
||||
@@ -168,7 +168,8 @@
|
||||
<allowInsecureRegistries>true</allowInsecureRegistries>
|
||||
<from>
|
||||
<!--使用openjdk官方镜像,tag是8-jdk-stretch,表示镜像的操作系统是debian9,装好了jdk8-->
|
||||
<image>registry.cn-shanghai.aliyuncs.com/all_lib/eclipse-temurin:17.0.10_7-jdk-jammy</image>
|
||||
<image>
|
||||
registry.cn-shanghai.aliyuncs.com/all_lib/eclipse-temurin:17.0.10_7-jdk-jammy</image>
|
||||
</from>
|
||||
<to>
|
||||
<!-- 前缀名/命名空间/项目名:项目版本-->
|
||||
@@ -183,7 +184,8 @@
|
||||
</auth>
|
||||
</to>
|
||||
<outputPaths>
|
||||
<tar>${project.build.directory}/${project.artifactId}-${project.version}.tar</tar>
|
||||
<tar>
|
||||
${project.build.directory}/${project.artifactId}-${project.version}.tar</tar>
|
||||
</outputPaths>
|
||||
<!--容器相关的属性-->
|
||||
<container>
|
||||
|
||||
Reference in New Issue
Block a user