c4713a63f88a72a4aaabaa70fe4a7ea08262fa60..a284792b8d8555c8a60b2e226bf36f91311d7147
2025-04-16 hongjli
优化
a28479 对比 | 目录
2025-04-15 hongjli
优化
80096e 对比 | 目录
已修改3个文件
已添加1个文件
126 ■■■■■ 文件已修改
docs/UserController_API_Test.md 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/weiwojc/config/CorsConfig.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/weiwojc/config/SecurityConfig.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/weiwojc/controller/UserController.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/UserController_API_Test.md
@@ -194,7 +194,57 @@
     }
     ```
## 3. èŽ·å–ç”¨æˆ·ä¿¡æ¯æŽ¥å£
## 3. é€€å‡ºç™»å½•接口
### æŽ¥å£ä¿¡æ¯
- è¯·æ±‚路径:`/api/users/logout`
- è¯·æ±‚方法:POST
- è¯·æ±‚头:需要携带 token
### æµ‹è¯•用例
#### æˆåŠŸåœºæ™¯
1. æ­£å¸¸é€€å‡ºç™»å½•
   - è¯·æ±‚头:
     ```
     token: eyJhbGciOiJIUzI1NiJ9...
     ```
   - é¢„期响应:
     ```json
     {
         "code": 200,
         "message": "退出登录成功",
         "data": null
     }
     ```
#### å¤±è´¥åœºæ™¯
1. æœªæºå¸¦ token
   - è¯·æ±‚头:无 token
   - é¢„期响应:
     ```json
     {
         "code": 400,
         "message": "未登录状态",
         "data": null
     }
     ```
2. token æ— æ•ˆæˆ–已过期
   - è¯·æ±‚头:
     ```
     token: invalid_token
     ```
   - é¢„期响应:
     ```json
     {
         "code": 401,
         "message": "token无效或已过期",
         "data": null
     }
     ```
## 4. èŽ·å–ç”¨æˆ·ä¿¡æ¯æŽ¥å£
### æŽ¥å£ä¿¡æ¯
- è¯·æ±‚路径:`/api/users/info`
@@ -282,4 +332,5 @@
3. ç”¨æˆ·ä¿¡æ¯æŽ¥å£éœ€è¦æœ‰æ•ˆçš„ JWT token
4. å¯†ç åœ¨ä¼ è¾“过程中应该使用 HTTPS åР坆
5. å»ºè®®åœ¨æµ‹è¯•环境中使用测试数据库
6. æµ‹è¯•时注意清理测试数据,避免影响其他测试用例
6. æµ‹è¯•时注意清理测试数据,避免影响其他测试用例
7. é€€å‡ºç™»å½•后的 token ä¼šè¢«åŠ å…¥é»‘åå•ï¼Œæ— æ³•å†æ¬¡ä½¿ç”¨
src/main/java/com/weiwojc/config/CorsConfig.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,33 @@
package com.weiwojc.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class CorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        // å…è®¸è·¨åŸŸçš„æºï¼Œè¿™é‡Œè®¾ç½®ä¸ºå…è®¸æ‰€æœ‰æº
        config.addAllowedOriginPattern("*");
        // å…è®¸è·¨åŸŸçš„请求头
        config.addAllowedHeader("*");
        // å…è®¸è·¨åŸŸçš„请求方法
        config.addAllowedMethod("*");
        // å…è®¸æºå¸¦è®¤è¯ä¿¡æ¯ï¼ˆtoken)
        config.setAllowCredentials(true);
        // æš´éœ²å“åº”头
        config.addExposedHeader("*");
        // è®¾ç½®è·¨åŸŸè¯·æ±‚的有效期,单位为秒
        config.setMaxAge(3600L);
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}
src/main/java/com/weiwojc/config/SecurityConfig.java
@@ -12,6 +12,9 @@
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
@Configuration
@EnableWebSecurity
@@ -23,6 +26,7 @@
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .cors(cors -> cors.configurationSource(corsConfigurationSource()))
            .csrf(AbstractHttpConfigurer::disable)
            .sessionManagement(session -> session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS))
@@ -35,6 +39,21 @@
    }
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.addAllowedOriginPattern("*");
        configuration.addAllowedMethod("*");
        configuration.addAllowedHeader("*");
        configuration.setAllowCredentials(true);
        configuration.addExposedHeader("*");
        configuration.setMaxAge(3600L);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
src/main/java/com/weiwojc/controller/UserController.java
@@ -6,6 +6,7 @@
import com.weiwojc.model.entity.User;
import com.weiwojc.service.UserService;
import com.weiwojc.utils.JwtUtils;
import com.weiwojc.utils.TokenBlacklistManager;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
@@ -18,6 +19,7 @@
    private final UserService userService;
    private final JwtUtils jwtUtils;
    private final TokenBlacklistManager tokenBlacklistManager;
    @PostMapping("/register")
    public Result<User> register(@Valid @RequestBody UserRegisterDTO registerDTO) {
@@ -31,6 +33,23 @@
        return Result.success("登录成功", token);
    }
    @PostMapping("/logout")
    public Result<String> logout(HttpServletRequest request) {
        String token = request.getHeader("token");
        if (token == null || token.isEmpty()) {
            return Result.error("未登录状态");
        }
        // éªŒè¯token是否有效
        if (!jwtUtils.validateToken(token)) {
            return Result.unauthorized("token无效或已过期");
        }
        // å°†token加入黑名单
        tokenBlacklistManager.addToBlacklist(token);
        return Result.success("退出登录成功");
    }
    @GetMapping("/info")
    public Result<User> getUserInfo(HttpServletRequest request) {
        String token = request.getHeader("token");