diff --git a/docs/JWT认证使用说明.md b/docs/JWT认证使用说明.md new file mode 100644 index 0000000..74ad4b7 --- /dev/null +++ b/docs/JWT认证使用说明.md @@ -0,0 +1,160 @@ +# JWT认证使用说明 + +## 概述 + +系统已从手动传递操作者信息的头部参数改为使用JWT(JSON Web Token)进行身份认证。这种方式更加安全、标准化,并且符合REST API的最佳实践。 + +## 认证流程 + +### 1. 用户登录获取JWT令牌 + +```http +POST /api/auth/login +Content-Type: application/json + +{ + "username": "your_username", + "password": "your_password" +} +``` + +响应示例: +```json +{ + "token": "eyJhbGciOiJIUzI1NiJ9...", + "userType": "AGENT", + "userId": 123, + "username": "your_username" +} +``` + +### 2. 使用JWT令牌调用受保护的接口 + +在请求头中添加 `Authorization` 头: + +```http +POST /api/link/generate +Authorization: Bearer eyJhbGciOiJIUzI1NiJ9... +Content-Type: application/json + +{ + "times": 10, + "perTimeQuantity": 5 +} +``` + +## 链接生成接口 + +### 接口地址 +`POST /api/link/generate` + +### 请求头 +- `Authorization: Bearer {JWT_TOKEN}` - 必需,JWT认证令牌 +- `Content-Type: application/json` - 必需 + +### 请求参数 +```json +{ + "times": 10, // 本次打脚本的次数 + "perTimeQuantity": 5 // 每次打的数量 +} +``` + +### 响应示例 +```json +{ + "batchId": 456, + "deductPoints": 50, + "expireAt": "2024-01-15T16:30:00", + "codeNos": ["ABC12345", "DEF67890", ...] +} +``` + +## 权限控制 + +### 代理用户 +- 只能为自己生成链接 +- 必须检查积分余额 +- 生成链接时扣除相应积分 + +### 管理员用户 +- 只能为自己生成链接 +- 跳过积分检查 +- 不扣除积分 + +## 安全特性 + +1. **JWT令牌验证**:每个请求都会验证JWT令牌的有效性 +2. **自动过期**:JWT令牌有自动过期时间(默认30分钟) +3. **用户身份验证**:从JWT中自动提取用户ID、用户类型等信息 +4. **权限控制**:基于用户类型进行不同的业务逻辑处理 + +## 错误处理 + +### 常见错误 + +1. **缺少认证令牌** + ```json + { + "error": "用户未认证" + } + ``` + +2. **令牌无效或过期** + ```json + { + "error": "JWT token validation failed" + } + ``` + +3. **权限不足** + ```json + { + "error": "非法操作者类型" + } + ``` + +## 技术实现 + +### 核心组件 + +1. **JwtService**:JWT令牌的生成和解析 +2. **JwtAuthenticationFilter**:自动处理JWT认证的Web过滤器 +3. **SecurityConfig**:Spring Security配置,定义哪些接口需要认证 +4. **LinkController**:使用Spring Security上下文获取用户信息 + +### 认证流程 + +``` +请求 → JwtAuthenticationFilter → JWT解析 → 创建认证对象 → Spring Security上下文 → 控制器获取用户信息 +``` + +## 迁移说明 + +### 从旧版本迁移 + +如果您之前使用的是手动传递操作者信息的头部参数: + +**旧方式(已废弃):** +```http +X-Operator-Id: 123 +X-Operator-Type: AGENT +``` + +**新方式:** +```http +Authorization: Bearer eyJhbGciOiJIUzI1NiJ9... +``` + +### 兼容性 + +- 旧的头参数方式已被完全移除 +- 所有链接相关接口现在都需要JWT认证 +- 确保在调用接口前先获取有效的JWT令牌 + +## 最佳实践 + +1. **令牌管理**:客户端应妥善保存JWT令牌,并在过期前刷新 +2. **安全传输**:始终使用HTTPS传输JWT令牌 +3. **错误处理**:客户端应处理认证失败的情况,引导用户重新登录 +4. **日志记录**:系统会自动记录所有认证相关的操作日志 diff --git a/src/main/java/com/gameplatform/server/controller/UserController.java b/src/main/java/com/gameplatform/server/controller/UserController.java deleted file mode 100644 index d4f81de..0000000 --- a/src/main/java/com/gameplatform/server/controller/UserController.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.gameplatform.server.controller; - -import com.gameplatform.server.model.dto.account.AccountCreateRequest; -import com.gameplatform.server.model.dto.account.AccountResponse; -import com.gameplatform.server.model.dto.account.AccountUpdateRequest; -import com.gameplatform.server.model.dto.common.PageResult; -import com.gameplatform.server.service.account.AccountService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.validation.Valid; -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.*; -import reactor.core.publisher.Mono; - -/** - * 用户接口控制器 - 基于UserAccount实体 - * 提供用户账户的基本CRUD操作 - */ -@RestController -@RequestMapping("/api/users") -@Tag(name = "用户账户管理", description = "用户账户的增删改查操作") -public class UserController { - private final AccountService accountService; - - public UserController(AccountService accountService) { - this.accountService = accountService; - } - - /** - * 根据ID获取用户账户信息 - */ - @GetMapping("/{id}") - @Operation(summary = "获取用户详情", description = "根据用户ID获取用户详细信息") - public Mono getById(@Parameter(description = "用户ID") @PathVariable Long id) { - return accountService.get(id); - } - - /** - * 分页查询用户列表 - */ - @GetMapping - @Operation(summary = "获取用户列表", description = "分页获取用户列表,支持按用户类型、状态、关键词筛选") - public Mono> list( - @Parameter(description = "用户类型:ADMIN 或 AGENT") @RequestParam(value = "userType", required = false) String userType, - @Parameter(description = "账户状态:ENABLED 或 DISABLED") @RequestParam(value = "status", required = false) String status, - @Parameter(description = "搜索关键词") @RequestParam(value = "keyword", required = false) String keyword, - @Parameter(description = "页码,默认1") @RequestParam(value = "page", defaultValue = "1") Integer page, - @Parameter(description = "每页大小,默认20") @RequestParam(value = "size", defaultValue = "20") Integer size - ) { - return accountService.list(userType, status, keyword, page, size); - } - - /** - * 创建新用户账户 - */ - @PostMapping - @ResponseStatus(HttpStatus.CREATED) - @Operation(summary = "创建用户", description = "创建新的代理用户账户") - public Mono create(@Valid @RequestBody AccountCreateRequest request) { - return accountService.create(request); - } - - /** - * 更新用户账户信息 - */ - @PutMapping("/{id}") - @Operation(summary = "更新用户", description = "更新用户账户信息") - public Mono update(@Parameter(description = "用户ID") @PathVariable Long id, @Valid @RequestBody AccountUpdateRequest request) { - return accountService.update(id, request); - } - - /** - * 启用用户账户 - */ - @PostMapping("/{id}/enable") - @ResponseStatus(HttpStatus.NO_CONTENT) - @Operation(summary = "启用用户", description = "启用指定用户账户") - public Mono enable(@Parameter(description = "用户ID") @PathVariable Long id) { - return accountService.setStatus(id, "ENABLED").then(); - } - - /** - * 禁用用户账户 - */ - @PostMapping("/{id}/disable") - @ResponseStatus(HttpStatus.NO_CONTENT) - @Operation(summary = "禁用用户", description = "禁用指定用户账户") - public Mono disable(@Parameter(description = "用户ID") @PathVariable Long id) { - return accountService.setStatus(id, "DISABLED").then(); - } -} \ No newline at end of file diff --git a/src/main/java/com/gameplatform/server/controller/link/LinkController.java b/src/main/java/com/gameplatform/server/controller/link/LinkController.java index ef03747..29b1d99 100644 --- a/src/main/java/com/gameplatform/server/controller/link/LinkController.java +++ b/src/main/java/com/gameplatform/server/controller/link/LinkController.java @@ -3,18 +3,26 @@ package com.gameplatform.server.controller.link; import com.gameplatform.server.model.dto.link.LinkGenerateRequest; import com.gameplatform.server.model.dto.link.LinkGenerateResponse; import com.gameplatform.server.service.link.LinkGenerationService; +import io.jsonwebtoken.Claims; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.ReactiveSecurityContextHolder; import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; - @RestController @RequestMapping("/api/link") -@Tag(name = "链接管理", description = "生成链接与二维码代理") +@Tag(name = "链接管理", description = "链接生成和管理相关接口") public class LinkController { + private static final Logger log = LoggerFactory.getLogger(LinkController.class); + private final LinkGenerationService linkGenerationService; public LinkController(LinkGenerationService linkGenerationService) { @@ -22,27 +30,87 @@ public class LinkController { } @PostMapping("/generate") - @ResponseStatus(HttpStatus.CREATED) - @Operation(summary = "生成链接批次", description = "times * perTimeQuantity = 目标点数;代理需扣点,管理员不扣") - public Mono generate(@Valid @RequestBody LinkGenerateRequest req, - @RequestHeader(value = "X-Operator-Id", required = false) Long operatorId, - @RequestHeader(value = "X-Operator-Type", required = false) String operatorType) { - // 暂时用两个 Header 传操作者信息;后续接入 JWT 解析 - Long targetAccountId = req.getAgentAccountId() != null ? req.getAgentAccountId() : operatorId; - return linkGenerationService.generateLinks(operatorId, safeUpper(operatorType), targetAccountId, - defaultInt(req.getTimes(), 0), defaultInt(req.getPerTimeQuantity(), 0)) - .map(r -> { - LinkGenerateResponse resp = new LinkGenerateResponse(); - resp.setBatchId(r.getBatchId()); - resp.setDeductPoints(r.getNeedPoints()); - resp.setExpireAt(r.getExpireAt()); - resp.setCodeNos(r.getCodeNos()); - return resp; + @ResponseStatus(HttpStatus.OK) + @Operation(summary = "生成链接批次", description = "生成指定数量的链接批次。所有用户(管理员和代理商)都只能为自己生成链接,代理用户生成链接时会扣除积分,管理员生成链接时不扣除积分") + public Mono generateLinks(@Valid @RequestBody LinkGenerateRequest request, + Authentication authentication) { + log.info("=== 开始处理链接生成请求 ==="); + log.info("请求参数: times={}, perTimeQuantity={}", + request.getTimes(), request.getPerTimeQuantity()); + + log.info("=== 开始检查认证信息 ==="); + log.info("Authentication: {}", authentication); + + if (authentication == null) { + log.error("=== 认证失败:Authentication为空 ==="); + return Mono.error(new IllegalArgumentException("用户未认证:Authentication为空")); + } + + log.info("Authentication获取成功: {}", authentication); + log.info("Authentication是否已认证: {}", authentication.isAuthenticated()); + log.info("Authentication的principal: {}", authentication.getPrincipal()); + log.info("Authentication的authorities: {}", authentication.getAuthorities()); + log.info("Authentication的details: {}", authentication.getDetails()); + + if (!authentication.isAuthenticated()) { + log.error("=== 认证失败:Authentication未通过验证 ==="); + log.error("Authentication详情: {}", authentication); + return Mono.error(new IllegalArgumentException("用户未认证:Authentication未通过验证")); + } + + log.info("=== 认证验证通过 ==="); + + // 从认证对象中获取用户信息 + log.info("开始解析Claims信息"); + Claims claims = (Claims) authentication.getDetails(); + if (claims == null) { + log.error("=== 认证失败:Claims为空 ==="); + log.error("Authentication details: {}", authentication.getDetails()); + return Mono.error(new IllegalArgumentException("用户未认证:Claims为空")); + } + + log.info("Claims获取成功,开始解析用户信息"); + log.info("Claims内容: {}", claims); + log.info("Claims的subject: {}", claims.getSubject()); + log.info("Claims的issuedAt: {}", claims.getIssuedAt()); + log.info("Claims的expiration: {}", claims.getExpiration()); + + Long operatorId = claims.get("userId", Long.class); + String operatorType = claims.get("userType", String.class); + String username = claims.get("username", String.class); + + log.info("解析出的用户信息 - operatorId: {}, operatorType: {}, username: {}", + operatorId, operatorType, username); + + if (operatorId == null || operatorType == null) { + log.error("=== 认证失败:缺少必要的用户信息 ==="); + log.error("operatorId: {}, operatorType: {}, username: {}", operatorId, operatorType, username); + log.error("Claims中所有键: {}", claims.keySet()); + return Mono.error(new IllegalArgumentException("用户未认证:缺少必要的用户信息")); + } + + log.info("=== 用户认证信息完整,开始处理业务逻辑 ==="); + log.info("操作者信息: operatorId={}, operatorType={}, username={}", + operatorId, operatorType, username); + log.info("业务参数: times={}, perTimeQuantity={}", + request.getTimes(), request.getPerTimeQuantity()); + + return linkGenerationService.generateLinks(operatorId, operatorType, + request.getTimes(), request.getPerTimeQuantity()) + .map(result -> { + log.info("链接生成成功,batchId: {}, 扣除积分: {}, 过期时间: {}", + result.getBatchId(), result.getNeedPoints(), result.getExpireAt()); + LinkGenerateResponse response = new LinkGenerateResponse(); + response.setBatchId(result.getBatchId()); + response.setDeductPoints(result.getNeedPoints()); + response.setExpireAt(result.getExpireAt()); + response.setCodeNos(result.getCodeNos()); + return response; + }) + .doOnError(error -> { + log.error("链接生成失败: {}", error.getMessage(), error); }); } - - private static String safeUpper(String s) { return s == null ? null : s.toUpperCase(); } - private static int defaultInt(Integer v, int d) { return v == null ? d : v; } } diff --git a/src/main/java/com/gameplatform/server/exception/GlobalExceptionHandler.java b/src/main/java/com/gameplatform/server/exception/GlobalExceptionHandler.java index aa0db4a..0169e7f 100644 --- a/src/main/java/com/gameplatform/server/exception/GlobalExceptionHandler.java +++ b/src/main/java/com/gameplatform/server/exception/GlobalExceptionHandler.java @@ -6,6 +6,9 @@ import org.springframework.http.HttpStatus; import org.springframework.web.bind.support.WebExchangeBindException; import org.springframework.web.server.ResponseStatusException; import org.springframework.web.server.ServerWebInputException; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.core.AuthenticationException; import jakarta.validation.ConstraintViolation; import jakarta.validation.ConstraintViolationException; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -22,21 +25,45 @@ public class GlobalExceptionHandler { @ExceptionHandler(IllegalArgumentException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public Object handleBadRequest(IllegalArgumentException e) { - log.info("400 BadRequest: {}", e.getMessage()); + log.warn("400 BadRequest: {} - Stack: {}", e.getMessage(), getStackTrace(e)); return body(HttpStatus.BAD_REQUEST.value(), e.getMessage()); } @ExceptionHandler(IllegalStateException.class) @ResponseStatus(HttpStatus.FORBIDDEN) public Object handleForbidden(IllegalStateException e) { - log.info("403 Forbidden: {}", e.getMessage()); + log.warn("403 Forbidden: {} - Stack: {}", e.getMessage(), getStackTrace(e)); return body(HttpStatus.FORBIDDEN.value(), e.getMessage()); } + // 认证相关异常处理 + @ExceptionHandler(AuthenticationException.class) + @ResponseStatus(HttpStatus.UNAUTHORIZED) + public Object handleAuthenticationException(AuthenticationException e) { + log.warn("401 Authentication Failed: {} - Type: {} - Stack: {}", + e.getMessage(), e.getClass().getSimpleName(), getStackTrace(e)); + return body(HttpStatus.UNAUTHORIZED.value(), "认证失败: " + e.getMessage()); + } + + @ExceptionHandler(BadCredentialsException.class) + @ResponseStatus(HttpStatus.UNAUTHORIZED) + public Object handleBadCredentials(BadCredentialsException e) { + log.warn("401 Bad Credentials: {} - Stack: {}", e.getMessage(), getStackTrace(e)); + return body(HttpStatus.UNAUTHORIZED.value(), "用户名或密码错误"); + } + + @ExceptionHandler(AccessDeniedException.class) + @ResponseStatus(HttpStatus.FORBIDDEN) + public Object handleAccessDenied(AccessDeniedException e) { + log.warn("403 Access Denied: {} - Stack: {}", e.getMessage(), getStackTrace(e)); + return body(HttpStatus.FORBIDDEN.value(), "访问被拒绝: " + e.getMessage()); + } + @ExceptionHandler(WebExchangeBindException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public Object handleBindException(WebExchangeBindException e) { - log.info("400 ValidationError: {}", e.getMessage()); + log.warn("400 ValidationError: {} - Field errors: {} - Global errors: {}", + e.getMessage(), e.getFieldErrors().size(), e.getGlobalErrors().size()); var details = new java.util.LinkedHashMap(); e.getFieldErrors().forEach(fe -> details.put(fe.getField(), fe.getDefaultMessage())); e.getGlobalErrors().forEach(ge -> details.put(ge.getObjectName(), ge.getDefaultMessage())); @@ -46,7 +73,8 @@ public class GlobalExceptionHandler { @ExceptionHandler(ConstraintViolationException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public Object handleConstraintViolation(ConstraintViolationException e) { - log.info("400 ConstraintViolation: {}", e.getMessage()); + log.warn("400 ConstraintViolation: {} - Violations: {}", + e.getMessage(), e.getConstraintViolations().size()); var details = new java.util.LinkedHashMap(); for (ConstraintViolation v : e.getConstraintViolations()) { details.put(String.valueOf(v.getPropertyPath()), v.getMessage()); @@ -57,21 +85,24 @@ public class GlobalExceptionHandler { @ExceptionHandler(ServerWebInputException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public Object handleInput(ServerWebInputException e) { - log.info("400 InputError: {}", e.getMessage()); + log.warn("400 InputError: {} - Reason: {} - Stack: {}", + e.getMessage(), e.getReason(), getStackTrace(e)); return body(HttpStatus.BAD_REQUEST.value(), "请求解析失败: " + e.getReason()); } @ExceptionHandler(ResponseStatusException.class) public Object handleRse(ResponseStatusException e) { var status = e.getStatusCode(); - log.info("{} ResponseStatusException: {}", status, e.getReason()); + log.warn("{} ResponseStatusException: {} - Stack: {}", + status, e.getReason(), getStackTrace(e)); return body(status.value(), e.getReason()); } @ExceptionHandler(Exception.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public Object handleOther(Exception e) { - log.error("500 InternalServerError", e); + log.error("500 InternalServerError: {} - Type: {} - Stack: {}", + e.getMessage(), e.getClass().getSimpleName(), getStackTrace(e), e); return body(HttpStatus.INTERNAL_SERVER_ERROR.value(), "服务器内部错误"); } @@ -91,4 +122,12 @@ public class GlobalExceptionHandler { put("timestamp", Instant.now().toString()); }}; } + + private String getStackTrace(Exception e) { + StackTraceElement[] stackTrace = e.getStackTrace(); + if (stackTrace.length > 0) { + return stackTrace[0].toString(); + } + return "No stack trace available"; + } } diff --git a/src/main/java/com/gameplatform/server/model/dto/link/LinkGenerateRequest.java b/src/main/java/com/gameplatform/server/model/dto/link/LinkGenerateRequest.java index b054ce0..f3dae8d 100644 --- a/src/main/java/com/gameplatform/server/model/dto/link/LinkGenerateRequest.java +++ b/src/main/java/com/gameplatform/server/model/dto/link/LinkGenerateRequest.java @@ -7,15 +7,11 @@ public class LinkGenerateRequest { private Integer times; @Schema(description = "每次打的数量", example = "5") private Integer perTimeQuantity; - @Schema(description = "为哪个代理账户生成(管理员可指定,代理可省略或为自己)") - private Long agentAccountId; public Integer getTimes() { return times; } public void setTimes(Integer times) { this.times = times; } public Integer getPerTimeQuantity() { return perTimeQuantity; } public void setPerTimeQuantity(Integer perTimeQuantity) { this.perTimeQuantity = perTimeQuantity; } - public Long getAgentAccountId() { return agentAccountId; } - public void setAgentAccountId(Long agentAccountId) { this.agentAccountId = agentAccountId; } } diff --git a/src/main/java/com/gameplatform/server/security/JwtAuthenticationFilter.java b/src/main/java/com/gameplatform/server/security/JwtAuthenticationFilter.java new file mode 100644 index 0000000..fa76b82 --- /dev/null +++ b/src/main/java/com/gameplatform/server/security/JwtAuthenticationFilter.java @@ -0,0 +1,123 @@ +package com.gameplatform.server.security; + +import io.jsonwebtoken.Claims; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextImpl; +import org.springframework.security.core.context.ReactiveSecurityContextHolder; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebFilter; +import org.springframework.web.server.WebFilterChain; +import reactor.core.publisher.Mono; + +import java.util.Collections; + +@Component +public class JwtAuthenticationFilter implements WebFilter { + private static final Logger log = LoggerFactory.getLogger(JwtAuthenticationFilter.class); + + private final JwtService jwtService; + + public JwtAuthenticationFilter(JwtService jwtService) { + this.jwtService = jwtService; + } + + @Override + public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { + String path = exchange.getRequest().getPath().value(); + String method = exchange.getRequest().getMethod().name(); + + log.info("=== JWT过滤器开始处理请求 ==="); + log.info("请求路径: {}, 请求方法: {}", path, method); + + String authHeader = exchange.getRequest().getHeaders().getFirst(HttpHeaders.AUTHORIZATION); + log.info("Authorization头: {}", authHeader != null ? authHeader.substring(0, Math.min(20, authHeader.length())) + "..." : "null"); + + if (authHeader == null) { + log.info("未找到Authorization头,跳过JWT认证,继续处理请求"); + return chain.filter(exchange); + } + + if (!authHeader.startsWith("Bearer ")) { + log.warn("Authorization头格式无效,期望格式: 'Bearer ',实际: {}", authHeader); + log.info("跳过JWT认证,继续处理请求"); + return chain.filter(exchange); + } + + String token = authHeader.substring(7); + log.info("开始处理JWT token,token长度: {}", token.length()); + log.debug("JWT token内容: {}", token); + + try { + log.info("开始解析JWT token"); + Claims claims = jwtService.parse(token); + log.info("JWT token解析成功"); + + Long userId = claims.get("userId", Long.class); + String userType = claims.get("userType", String.class); + String username = claims.get("username", String.class); + String subject = claims.getSubject(); + + log.info("JWT claims解析结果:"); + log.info(" - subject: {}", subject); + log.info(" - userId: {}", userId); + log.info(" - userType: {}", userType); + log.info(" - username: {}", username); + log.info(" - issuedAt: {}", claims.getIssuedAt()); + log.info(" - expiration: {}", claims.getExpiration()); + log.info(" - 所有claims键: {}", claims.keySet()); + + if (userId == null || userType == null || username == null) { + log.warn("JWT token中缺少必要的claims信息"); + log.warn(" - userId: {}", userId); + log.warn(" - userType: {}", userType); + log.warn(" - username: {}", username); + log.info("跳过JWT认证,继续处理请求"); + return chain.filter(exchange); + } + + // 创建Spring Security的Authentication对象 + log.info("开始创建Authentication对象"); + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + username, // principal + null, // credentials (不需要密码) + Collections.singletonList(new SimpleGrantedAuthority("ROLE_" + userType.toUpperCase())) + ); + + // 设置认证详情,包含JWT claims信息 + authentication.setDetails(claims); + + log.info("Authentication对象创建成功: {}", authentication); + log.info("Authentication是否已认证: {}", authentication.isAuthenticated()); + log.info("Authentication的principal: {}", authentication.getPrincipal()); + log.info("Authentication的authorities: {}", authentication.getAuthorities()); + log.info("Authentication的details: {}", authentication.getDetails()); + + // 创建安全上下文并设置认证信息 + SecurityContext securityContext = new SecurityContextImpl(authentication); + + log.info("=== JWT token验证成功,设置安全上下文 ==="); + log.info("用户: {} (ID: {}, 类型: {}) 在路径: {} 上JWT验证通过", + username, userId, userType, path); + + // 将安全上下文设置到ReactiveSecurityContextHolder中 + return chain.filter(exchange) + .contextWrite(ReactiveSecurityContextHolder.withSecurityContext(Mono.just(securityContext))); + + } catch (Exception e) { + log.error("=== JWT token验证失败 ==="); + log.error("请求路径: {}", path); + log.error("Authorization头: {}", authHeader); + log.error("错误详情: {}", e.getMessage(), e); + log.info("JWT认证失败,继续处理请求(未认证状态)"); + } + + log.info("JWT过滤器处理完成,继续处理请求"); + return chain.filter(exchange); + } +} diff --git a/src/main/java/com/gameplatform/server/security/JwtService.java b/src/main/java/com/gameplatform/server/security/JwtService.java index c84e6a3..481fb64 100644 --- a/src/main/java/com/gameplatform/server/security/JwtService.java +++ b/src/main/java/com/gameplatform/server/security/JwtService.java @@ -27,9 +27,14 @@ public class JwtService { byte[] bytes = secret.length() < 32 ? (secret + "_pad_to_32_chars_secret_key_value").getBytes() : secret.getBytes(); this.key = Keys.hmacShaKeyFor(bytes); this.accessTokenMinutes = accessTokenMinutes; + log.info("JWT服务初始化完成 - 密钥长度: {} bytes, token过期时间: {} 分钟", bytes.length, accessTokenMinutes); } public String generateToken(String subject, String userType, Long userId, String username, Map extra) { + log.info("=== 开始生成JWT token ==="); + log.info("生成参数: subject={}, userType={}, userId={}, username={}, extra={}", + subject, userType, userId, username, extra); + Instant now = Instant.now(); var builder = Jwts.builder() .setSubject(subject) @@ -41,14 +46,44 @@ public class JwtService { if (extra != null) { extra.forEach(builder::claim); } + + log.info("JWT builder配置完成,开始签名"); String token = builder.signWith(key, SignatureAlgorithm.HS256).compact(); - if (log.isDebugEnabled()) { - log.debug("JWT generated subject={}, userType={}, userId={}, username={} expInMin={}", subject, userType, userId, username, accessTokenMinutes); - } + + log.info("=== JWT token生成成功 ==="); + log.info("token长度: {} 字符", token.length()); + log.info("过期时间: {} 分钟后", accessTokenMinutes); + log.info("完整token: {}", token); + return token; } public io.jsonwebtoken.Claims parse(String token) { - return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody(); + log.info("=== 开始解析JWT token ==="); + log.info("token长度: {} 字符", token.length()); + log.debug("完整token: {}", token); + + try { + log.info("开始验证JWT签名"); + io.jsonwebtoken.Claims claims = Jwts.parserBuilder() + .setSigningKey(key) + .build() + .parseClaimsJws(token) + .getBody(); + + log.info("=== JWT token解析成功 ==="); + log.info("解析结果:"); + log.info(" - subject: {}", claims.getSubject()); + log.info(" - issuedAt: {}", claims.getIssuedAt()); + log.info(" - expiration: {}", claims.getExpiration()); + log.info(" - 所有claims: {}", claims); + + return claims; + } catch (Exception e) { + log.error("=== JWT token解析失败 ==="); + log.error("token: {}", token); + log.error("错误详情: {}", e.getMessage(), e); + throw e; + } } } diff --git a/src/main/java/com/gameplatform/server/security/SecurityConfig.java b/src/main/java/com/gameplatform/server/security/SecurityConfig.java index 1800fc2..c8d745a 100644 --- a/src/main/java/com/gameplatform/server/security/SecurityConfig.java +++ b/src/main/java/com/gameplatform/server/security/SecurityConfig.java @@ -1,37 +1,107 @@ package com.gameplatform.server.security; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; - +import org.springframework.security.authentication.ReactiveAuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.config.web.server.SecurityWebFiltersOrder; import org.springframework.security.config.web.server.ServerHttpSecurity; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.server.SecurityWebFilterChain; +import org.springframework.security.web.server.context.ServerSecurityContextRepository; +import org.springframework.security.web.server.context.WebSessionServerSecurityContextRepository; +import reactor.core.publisher.Mono; @Configuration @EnableWebFluxSecurity public class SecurityConfig { + private static final Logger log = LoggerFactory.getLogger(SecurityConfig.class); + + @Autowired + private JwtAuthenticationFilter jwtAuthenticationFilter; @Bean public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { - return http + log.info("=== 开始配置Spring Security安全链 ==="); + + SecurityWebFilterChain chain = http .csrf(ServerHttpSecurity.CsrfSpec::disable) .cors(cors -> {}) .httpBasic(ServerHttpSecurity.HttpBasicSpec::disable) .formLogin(ServerHttpSecurity.FormLoginSpec::disable) + .securityContextRepository(securityContextRepository()) + .authenticationManager(authenticationManager()) .authorizeExchange(ex -> ex .pathMatchers("/actuator/**").permitAll() .pathMatchers(HttpMethod.POST, "/api/auth/login").permitAll() .pathMatchers(HttpMethod.GET, "/api/auth/me").permitAll() + .pathMatchers("/api/link/**").authenticated() // 链接接口需要认证 .anyExchange().permitAll() // 其他接口后续再收紧 ) + // 关键:将JWT过滤器集成到Security过滤链中,放在AUTHENTICATION位置 + .addFilterAt(jwtAuthenticationFilter, SecurityWebFiltersOrder.AUTHENTICATION) .build(); + + log.info("=== Spring Security安全链配置完成 ==="); + log.info("安全配置详情:"); + log.info(" - CSRF: 已禁用"); + log.info(" - CORS: 已启用"); + log.info(" - HTTP Basic: 已禁用"); + log.info(" - Form Login: 已禁用"); + log.info(" - JWT过滤器: 已集成到Security链中 (AUTHENTICATION位置)"); + log.info(" - 路径权限配置:"); + log.info(" * /actuator/** -> 允许所有"); + log.info(" * POST /api/auth/login -> 允许所有"); + log.info(" * GET /api/auth/me -> 允许所有"); + log.info(" * /api/link/** -> 需要认证"); + log.info(" * 其他路径 -> 允许所有"); + + return chain; + } + + @Bean + public ReactiveAuthenticationManager authenticationManager() { + log.info("创建JWT认证管理器"); + return authentication -> { + log.info("=== JWT认证管理器开始处理认证 ==="); + log.info("认证对象: {}", authentication); + + if (authentication instanceof UsernamePasswordAuthenticationToken) { + UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) authentication; + log.info("处理UsernamePasswordAuthenticationToken认证"); + log.info("Principal: {}", auth.getPrincipal()); + log.info("Credentials: {}", auth.getCredentials()); + log.info("Authorities: {}", auth.getAuthorities()); + log.info("Details: {}", auth.getDetails()); + log.info("是否已认证: {}", auth.isAuthenticated()); + + // 如果已经通过JWT过滤器认证,直接返回 + if (auth.isAuthenticated()) { + log.info("认证对象已经通过验证,返回成功"); + return Mono.just(auth); + } + } + + log.info("认证对象未通过验证,返回失败"); + return Mono.empty(); + }; + } + + @Bean + public ServerSecurityContextRepository securityContextRepository() { + log.info("创建安全上下文仓库"); + return new WebSessionServerSecurityContextRepository(); } @Bean public PasswordEncoder passwordEncoder() { + log.info("创建BCrypt密码编码器"); return new BCryptPasswordEncoder(); } } diff --git a/src/main/java/com/gameplatform/server/service/link/LinkGenerationService.java b/src/main/java/com/gameplatform/server/service/link/LinkGenerationService.java index 16751d1..e4fc2f6 100644 --- a/src/main/java/com/gameplatform/server/service/link/LinkGenerationService.java +++ b/src/main/java/com/gameplatform/server/service/link/LinkGenerationService.java @@ -46,46 +46,43 @@ public class LinkGenerationService { @Transactional public Mono generateLinks(Long operatorId, String operatorType, - Long targetAccountId, int times, int perTimeQuantity) { - return Mono.fromCallable(() -> doGenerate(operatorId, operatorType, targetAccountId, times, perTimeQuantity)) + return Mono.fromCallable(() -> doGenerate(operatorId, operatorType, times, perTimeQuantity)) .subscribeOn(Schedulers.boundedElastic()); } private GenerateResult doGenerate(Long operatorId, String operatorType, - Long targetAccountId, int times, int perTimeQuantity) { if (times <= 0 || perTimeQuantity <= 0) { throw new IllegalArgumentException("times 与 perTimeQuantity 必须为正整数"); } - UserAccount target = userAccountMapper.findById(targetAccountId); - if (target == null) { - throw new IllegalArgumentException("目标账户不存在"); + // 获取操作者账户信息 + UserAccount operator = userAccountMapper.findById(operatorId); + if (operator == null) { + throw new IllegalArgumentException("操作者账户不存在"); } + boolean isAdminOperator = "ADMIN".equalsIgnoreCase(operatorType); if (!isAdminOperator && !"AGENT".equalsIgnoreCase(operatorType)) { throw new IllegalArgumentException("非法操作者类型"); } - if (!"AGENT".equalsIgnoreCase(target.getUserType())) { - throw new IllegalArgumentException("仅支持为代理账户生成链接"); - } long needPoints = (long) times * (long) perTimeQuantity; if (log.isDebugEnabled()) { - log.debug("generateLinks operatorId={} operatorType={} targetAccountId={} times={} perTimeQuantity={} needPoints={} expireHours={}", - operatorId, operatorType, targetAccountId, times, perTimeQuantity, needPoints, expireHours); + log.debug("generateLinks operatorId={} operatorType={} times={} perTimeQuantity={} needPoints={} expireHours={}", + operatorId, operatorType, times, perTimeQuantity, needPoints, expireHours); } if (!isAdminOperator) { // 代理商自操作,需扣点判断 - long balance = target.getPointsBalance() == null ? 0L : target.getPointsBalance(); + long balance = operator.getPointsBalance() == null ? 0L : operator.getPointsBalance(); if (balance < needPoints) { throw new IllegalStateException("点数不足"); } } LinkBatch batch = new LinkBatch(); - batch.setAgentId(target.getId()); + batch.setAgentId(operator.getId()); batch.setQuantity(times); batch.setTimes(times); batch.setBatchSize(perTimeQuantity); @@ -98,7 +95,7 @@ public class LinkGenerationService { for (int i = 0; i < times; i++) { LinkTask t = new LinkTask(); t.setBatchId(batch.getId()); - t.setAgentId(target.getId()); + t.setAgentId(operator.getId()); t.setCodeNo(generateCodeNo()); t.setTokenHash(DigestUtils.sha256Hex(generateToken())); t.setExpireAt(expireAt); @@ -109,11 +106,11 @@ public class LinkGenerationService { if (!isAdminOperator) { // 扣点流水 + 账户余额 - long before = target.getPointsBalance() == null ? 0L : target.getPointsBalance(); + long before = operator.getPointsBalance() == null ? 0L : operator.getPointsBalance(); long after = before - needPoints; AgentPointsTx tx = new AgentPointsTx(); - tx.setAccountId(target.getId()); + tx.setAccountId(operator.getId()); tx.setType("DEDUCT"); tx.setBeforePoints(before); tx.setDeltaPoints(-needPoints); @@ -124,7 +121,7 @@ public class LinkGenerationService { agentPointsTxMapper.insert(tx); UserAccount patch = new UserAccount(); - patch.setId(target.getId()); + patch.setId(operator.getId()); patch.setPointsBalance(after); userAccountMapper.update(patch); } diff --git a/target/classes/com/gameplatform/server/GamePlatformServerApplication.class b/target/classes/com/gameplatform/server/GamePlatformServerApplication.class new file mode 100644 index 0000000..91b7441 Binary files /dev/null and b/target/classes/com/gameplatform/server/GamePlatformServerApplication.class differ diff --git a/target/classes/com/gameplatform/server/config/CorsConfig.class b/target/classes/com/gameplatform/server/config/CorsConfig.class new file mode 100644 index 0000000..9b5d160 Binary files /dev/null and b/target/classes/com/gameplatform/server/config/CorsConfig.class differ diff --git a/target/classes/com/gameplatform/server/config/SwaggerConfig.class b/target/classes/com/gameplatform/server/config/SwaggerConfig.class new file mode 100644 index 0000000..651961f Binary files /dev/null and b/target/classes/com/gameplatform/server/config/SwaggerConfig.class differ diff --git a/target/classes/com/gameplatform/server/controller/admin/AccountController.class b/target/classes/com/gameplatform/server/controller/admin/AccountController.class new file mode 100644 index 0000000..db84bb3 Binary files /dev/null and b/target/classes/com/gameplatform/server/controller/admin/AccountController.class differ diff --git a/target/classes/com/gameplatform/server/controller/auth/AuthController$1.class b/target/classes/com/gameplatform/server/controller/auth/AuthController$1.class new file mode 100644 index 0000000..542d1f9 Binary files /dev/null and b/target/classes/com/gameplatform/server/controller/auth/AuthController$1.class differ diff --git a/target/classes/com/gameplatform/server/controller/auth/AuthController.class b/target/classes/com/gameplatform/server/controller/auth/AuthController.class new file mode 100644 index 0000000..da79dfb Binary files /dev/null and b/target/classes/com/gameplatform/server/controller/auth/AuthController.class differ diff --git a/target/classes/com/gameplatform/server/controller/link/LinkController.class b/target/classes/com/gameplatform/server/controller/link/LinkController.class index b04cd43..499d45f 100644 Binary files a/target/classes/com/gameplatform/server/controller/link/LinkController.class and b/target/classes/com/gameplatform/server/controller/link/LinkController.class differ diff --git a/target/classes/com/gameplatform/server/controller/link/QrProxyController.class b/target/classes/com/gameplatform/server/controller/link/QrProxyController.class index 04874d1..9e2cc3e 100644 Binary files a/target/classes/com/gameplatform/server/controller/link/QrProxyController.class and b/target/classes/com/gameplatform/server/controller/link/QrProxyController.class differ diff --git a/target/classes/com/gameplatform/server/exception/GlobalExceptionHandler$1.class b/target/classes/com/gameplatform/server/exception/GlobalExceptionHandler$1.class new file mode 100644 index 0000000..9851068 Binary files /dev/null and b/target/classes/com/gameplatform/server/exception/GlobalExceptionHandler$1.class differ diff --git a/target/classes/com/gameplatform/server/exception/GlobalExceptionHandler$2.class b/target/classes/com/gameplatform/server/exception/GlobalExceptionHandler$2.class new file mode 100644 index 0000000..b432144 Binary files /dev/null and b/target/classes/com/gameplatform/server/exception/GlobalExceptionHandler$2.class differ diff --git a/target/classes/com/gameplatform/server/exception/GlobalExceptionHandler.class b/target/classes/com/gameplatform/server/exception/GlobalExceptionHandler.class new file mode 100644 index 0000000..5b7ee92 Binary files /dev/null and b/target/classes/com/gameplatform/server/exception/GlobalExceptionHandler.class differ diff --git a/target/classes/com/gameplatform/server/mapper/account/UserAccountMapper.class b/target/classes/com/gameplatform/server/mapper/account/UserAccountMapper.class new file mode 100644 index 0000000..27e4f34 Binary files /dev/null and b/target/classes/com/gameplatform/server/mapper/account/UserAccountMapper.class differ diff --git a/target/classes/com/gameplatform/server/mapper/admin/AnnouncementMapper.class b/target/classes/com/gameplatform/server/mapper/admin/AnnouncementMapper.class new file mode 100644 index 0000000..a4a44f5 Binary files /dev/null and b/target/classes/com/gameplatform/server/mapper/admin/AnnouncementMapper.class differ diff --git a/target/classes/com/gameplatform/server/mapper/admin/OperationLogMapper.class b/target/classes/com/gameplatform/server/mapper/admin/OperationLogMapper.class new file mode 100644 index 0000000..93a8f9d Binary files /dev/null and b/target/classes/com/gameplatform/server/mapper/admin/OperationLogMapper.class differ diff --git a/target/classes/com/gameplatform/server/mapper/agent/AgentPointsTxMapper.class b/target/classes/com/gameplatform/server/mapper/agent/AgentPointsTxMapper.class new file mode 100644 index 0000000..53e1db6 Binary files /dev/null and b/target/classes/com/gameplatform/server/mapper/agent/AgentPointsTxMapper.class differ diff --git a/target/classes/com/gameplatform/server/mapper/agent/LinkBatchMapper.class b/target/classes/com/gameplatform/server/mapper/agent/LinkBatchMapper.class new file mode 100644 index 0000000..3dac129 Binary files /dev/null and b/target/classes/com/gameplatform/server/mapper/agent/LinkBatchMapper.class differ diff --git a/target/classes/com/gameplatform/server/mapper/agent/LinkTaskMapper.class b/target/classes/com/gameplatform/server/mapper/agent/LinkTaskMapper.class new file mode 100644 index 0000000..4484dab Binary files /dev/null and b/target/classes/com/gameplatform/server/mapper/agent/LinkTaskMapper.class differ diff --git a/target/classes/com/gameplatform/server/model/dto/account/AccountCreateRequest.class b/target/classes/com/gameplatform/server/model/dto/account/AccountCreateRequest.class new file mode 100644 index 0000000..a8f3453 Binary files /dev/null and b/target/classes/com/gameplatform/server/model/dto/account/AccountCreateRequest.class differ diff --git a/target/classes/com/gameplatform/server/model/dto/account/AccountResponse.class b/target/classes/com/gameplatform/server/model/dto/account/AccountResponse.class new file mode 100644 index 0000000..d33af3a Binary files /dev/null and b/target/classes/com/gameplatform/server/model/dto/account/AccountResponse.class differ diff --git a/target/classes/com/gameplatform/server/model/dto/account/AccountUpdateRequest.class b/target/classes/com/gameplatform/server/model/dto/account/AccountUpdateRequest.class new file mode 100644 index 0000000..4ee9faf Binary files /dev/null and b/target/classes/com/gameplatform/server/model/dto/account/AccountUpdateRequest.class differ diff --git a/target/classes/com/gameplatform/server/model/dto/account/ResetPasswordRequest.class b/target/classes/com/gameplatform/server/model/dto/account/ResetPasswordRequest.class new file mode 100644 index 0000000..9d718cc Binary files /dev/null and b/target/classes/com/gameplatform/server/model/dto/account/ResetPasswordRequest.class differ diff --git a/target/classes/com/gameplatform/server/model/dto/auth/LoginRequest.class b/target/classes/com/gameplatform/server/model/dto/auth/LoginRequest.class new file mode 100644 index 0000000..bf762f2 Binary files /dev/null and b/target/classes/com/gameplatform/server/model/dto/auth/LoginRequest.class differ diff --git a/target/classes/com/gameplatform/server/model/dto/auth/LoginResponse.class b/target/classes/com/gameplatform/server/model/dto/auth/LoginResponse.class new file mode 100644 index 0000000..2557f1e Binary files /dev/null and b/target/classes/com/gameplatform/server/model/dto/auth/LoginResponse.class differ diff --git a/target/classes/com/gameplatform/server/model/dto/common/PageResult.class b/target/classes/com/gameplatform/server/model/dto/common/PageResult.class new file mode 100644 index 0000000..e70f530 Binary files /dev/null and b/target/classes/com/gameplatform/server/model/dto/common/PageResult.class differ diff --git a/target/classes/com/gameplatform/server/model/dto/link/LinkGenerateRequest.class b/target/classes/com/gameplatform/server/model/dto/link/LinkGenerateRequest.class index 19260ea..4d8423f 100644 Binary files a/target/classes/com/gameplatform/server/model/dto/link/LinkGenerateRequest.class and b/target/classes/com/gameplatform/server/model/dto/link/LinkGenerateRequest.class differ diff --git a/target/classes/com/gameplatform/server/model/dto/link/LinkGenerateResponse.class b/target/classes/com/gameplatform/server/model/dto/link/LinkGenerateResponse.class index b0f2dd8..4d8597d 100644 Binary files a/target/classes/com/gameplatform/server/model/dto/link/LinkGenerateResponse.class and b/target/classes/com/gameplatform/server/model/dto/link/LinkGenerateResponse.class differ diff --git a/target/classes/com/gameplatform/server/model/entity/account/UserAccount.class b/target/classes/com/gameplatform/server/model/entity/account/UserAccount.class new file mode 100644 index 0000000..0670941 Binary files /dev/null and b/target/classes/com/gameplatform/server/model/entity/account/UserAccount.class differ diff --git a/target/classes/com/gameplatform/server/model/entity/admin/Announcement.class b/target/classes/com/gameplatform/server/model/entity/admin/Announcement.class new file mode 100644 index 0000000..cd8f533 Binary files /dev/null and b/target/classes/com/gameplatform/server/model/entity/admin/Announcement.class differ diff --git a/target/classes/com/gameplatform/server/model/entity/admin/OperationLog.class b/target/classes/com/gameplatform/server/model/entity/admin/OperationLog.class new file mode 100644 index 0000000..9679548 Binary files /dev/null and b/target/classes/com/gameplatform/server/model/entity/admin/OperationLog.class differ diff --git a/target/classes/com/gameplatform/server/model/entity/agent/AgentPointsTx.class b/target/classes/com/gameplatform/server/model/entity/agent/AgentPointsTx.class new file mode 100644 index 0000000..a2d34b7 Binary files /dev/null and b/target/classes/com/gameplatform/server/model/entity/agent/AgentPointsTx.class differ diff --git a/target/classes/com/gameplatform/server/model/entity/agent/LinkBatch.class b/target/classes/com/gameplatform/server/model/entity/agent/LinkBatch.class new file mode 100644 index 0000000..792655d Binary files /dev/null and b/target/classes/com/gameplatform/server/model/entity/agent/LinkBatch.class differ diff --git a/target/classes/com/gameplatform/server/model/entity/agent/LinkTask.class b/target/classes/com/gameplatform/server/model/entity/agent/LinkTask.class new file mode 100644 index 0000000..454a491 Binary files /dev/null and b/target/classes/com/gameplatform/server/model/entity/agent/LinkTask.class differ diff --git a/target/classes/com/gameplatform/server/security/JwtAuthenticationFilter.class b/target/classes/com/gameplatform/server/security/JwtAuthenticationFilter.class new file mode 100644 index 0000000..d04d60d Binary files /dev/null and b/target/classes/com/gameplatform/server/security/JwtAuthenticationFilter.class differ diff --git a/target/classes/com/gameplatform/server/security/JwtService.class b/target/classes/com/gameplatform/server/security/JwtService.class new file mode 100644 index 0000000..bfd4610 Binary files /dev/null and b/target/classes/com/gameplatform/server/security/JwtService.class differ diff --git a/target/classes/com/gameplatform/server/security/SecurityConfig.class b/target/classes/com/gameplatform/server/security/SecurityConfig.class new file mode 100644 index 0000000..9bf9570 Binary files /dev/null and b/target/classes/com/gameplatform/server/security/SecurityConfig.class differ diff --git a/target/classes/com/gameplatform/server/service/UserService.class b/target/classes/com/gameplatform/server/service/UserService.class new file mode 100644 index 0000000..c8c8941 Binary files /dev/null and b/target/classes/com/gameplatform/server/service/UserService.class differ diff --git a/target/classes/com/gameplatform/server/service/account/AccountService.class b/target/classes/com/gameplatform/server/service/account/AccountService.class new file mode 100644 index 0000000..058b41a Binary files /dev/null and b/target/classes/com/gameplatform/server/service/account/AccountService.class differ diff --git a/target/classes/com/gameplatform/server/service/auth/AuthService.class b/target/classes/com/gameplatform/server/service/auth/AuthService.class new file mode 100644 index 0000000..7324f12 Binary files /dev/null and b/target/classes/com/gameplatform/server/service/auth/AuthService.class differ diff --git a/target/classes/com/gameplatform/server/service/external/ScriptClient.class b/target/classes/com/gameplatform/server/service/external/ScriptClient.class index 67256bc..0e473a4 100644 Binary files a/target/classes/com/gameplatform/server/service/external/ScriptClient.class and b/target/classes/com/gameplatform/server/service/external/ScriptClient.class differ diff --git a/target/classes/com/gameplatform/server/service/link/LinkGenerationService$GenerateResult.class b/target/classes/com/gameplatform/server/service/link/LinkGenerationService$GenerateResult.class index e9e11e1..117c529 100644 Binary files a/target/classes/com/gameplatform/server/service/link/LinkGenerationService$GenerateResult.class and b/target/classes/com/gameplatform/server/service/link/LinkGenerationService$GenerateResult.class differ diff --git a/target/classes/com/gameplatform/server/service/link/LinkGenerationService.class b/target/classes/com/gameplatform/server/service/link/LinkGenerationService.class new file mode 100644 index 0000000..d14f526 Binary files /dev/null and b/target/classes/com/gameplatform/server/service/link/LinkGenerationService.class differ diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst index 7675023..ee336ee 100644 --- a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst +++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -8,38 +8,34 @@ com\gameplatform\server\model\dto\common\PageResult.class com\gameplatform\server\service\UserService.class com\gameplatform\server\controller\auth\AuthController.class com\gameplatform\server\GamePlatformServerApplication.class +com\gameplatform\server\service\link\LinkGenerationService$GenerateResult.class com\gameplatform\server\mapper\admin\AnnouncementMapper.class -com\gameplatform\server\model\dto\link\CreateLinkBatchResponse.class com\gameplatform\server\service\auth\AuthService.class com\gameplatform\server\config\SwaggerConfig.class com\gameplatform\server\mapper\account\UserAccountMapper.class com\gameplatform\server\service\account\AccountService.class -com\gameplatform\server\model\dto\link\CreateLinkBatchRequest.class -com\gameplatform\server\model\dto\link\LinkStatisticsResponse.class -com\gameplatform\server\service\link\QrCodeProxyService$CachedImage.class -com\gameplatform\server\service\link\QrCodeProxyService.class +com\gameplatform\server\security\JwtAuthenticationFilter.class +com\gameplatform\server\service\external\ScriptClient.class +com\gameplatform\server\model\dto\link\LinkGenerateResponse.class com\gameplatform\server\controller\auth\AuthController$1.class +com\gameplatform\server\model\dto\link\LinkGenerateRequest.class com\gameplatform\server\model\entity\admin\Announcement.class -com\gameplatform\server\controller\link\LinkTaskController.class -com\gameplatform\server\model\dto\link\LinkTaskResponse.class com\gameplatform\server\model\entity\agent\AgentPointsTx.class com\gameplatform\server\controller\admin\AccountController.class com\gameplatform\server\model\dto\auth\LoginRequest.class com\gameplatform\server\model\entity\account\UserAccount.class com\gameplatform\server\model\dto\auth\LoginResponse.class com\gameplatform\server\model\entity\agent\LinkTask.class +com\gameplatform\server\controller\link\LinkController.class com\gameplatform\server\exception\GlobalExceptionHandler$1.class com\gameplatform\server\mapper\agent\LinkBatchMapper.class com\gameplatform\server\security\JwtService.class -com\gameplatform\server\model\dto\link\LinkTaskQueryRequest.class com\gameplatform\server\mapper\admin\OperationLogMapper.class com\gameplatform\server\model\entity\agent\LinkBatch.class -com\gameplatform\server\controller\UserController.class com\gameplatform\server\security\SecurityConfig.class -com\gameplatform\server\service\link\LinkTaskService.class com\gameplatform\server\model\entity\admin\OperationLog.class com\gameplatform\server\model\dto\account\AccountResponse.class com\gameplatform\server\model\dto\account\AccountCreateRequest.class -com\gameplatform\server\config\ScheduleConfig.class +com\gameplatform\server\controller\link\QrProxyController.class com\gameplatform\server\model\dto\account\AccountUpdateRequest.class com\gameplatform\server\model\dto\account\ResetPasswordRequest.class diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst index baef7be..4966aa4 100644 --- a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -7,7 +7,6 @@ D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\service\aut D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\model\dto\auth\LoginRequest.java D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\controller\admin\AccountController.java D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\service\external\ScriptClient.java -D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\controller\UserController.java D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\mapper\agent\LinkBatchMapper.java D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\controller\link\QrProxyController.java D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\mapper\agent\LinkTaskMapper.java @@ -25,6 +24,7 @@ D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\model\dto\l D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\model\entity\agent\LinkTask.java D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\model\dto\account\AccountUpdateRequest.java D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\model\entity\admin\Announcement.java +D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\security\JwtAuthenticationFilter.java D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\model\entity\agent\AgentPointsTx.java D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\model\dto\auth\LoginResponse.java D:\project\gamePlatform\server\src\main\java\com\gameplatform\server\controller\link\LinkController.java diff --git a/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst b/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst deleted file mode 100644 index f558db7..0000000 --- a/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst +++ /dev/null @@ -1,2 +0,0 @@ -com\gameplatform\server\service\link\LinkGenerationServiceTest.class -com\gameplatform\server\service\link\LinkTaskServiceTest.class diff --git a/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst deleted file mode 100644 index 8743795..0000000 --- a/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst +++ /dev/null @@ -1,2 +0,0 @@ -D:\project\gamePlatform\server\src\test\java\com\gameplatform\server\service\link\LinkTaskServiceTest.java -D:\project\gamePlatform\server\src\test\java\com\gameplatform\server\service\link\LinkGenerationServiceTest.java