diff --git a/xianyu-common/src/main/java/top/biwin/xinayu/common/dto/response/FileUploadResponse.java b/xianyu-common/src/main/java/top/biwin/xinayu/common/dto/response/FileUploadResponse.java new file mode 100644 index 0000000..ef4e4cd --- /dev/null +++ b/xianyu-common/src/main/java/top/biwin/xinayu/common/dto/response/FileUploadResponse.java @@ -0,0 +1,21 @@ +package top.biwin.xinayu.common.dto.response; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +/** + * TODO + * + * @author wangli + * @since 2026-01-30 10:48 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class FileUploadResponse extends BaseResponse{ + + @JsonProperty("image_url") + private String imageUrl; +} diff --git a/xianyu-server/src/main/java/top/biwin/xinayu/server/config/SecurityConfig.java b/xianyu-server/src/main/java/top/biwin/xinayu/server/config/SecurityConfig.java index 7e1d033..b890bb4 100644 --- a/xianyu-server/src/main/java/top/biwin/xinayu/server/config/SecurityConfig.java +++ b/xianyu-server/src/main/java/top/biwin/xinayu/server/config/SecurityConfig.java @@ -42,101 +42,102 @@ import top.biwin.xinayu.server.security.JwtAuthenticationFilter; @EnableWebSecurity @EnableMethodSecurity(prePostEnabled = true) public class SecurityConfig { - @Autowired - private JwtAuthenticationFilter jwtAuthenticationFilter; + @Autowired + private JwtAuthenticationFilter jwtAuthenticationFilter; - @Autowired - private UserDetailsService userDetailsService; + @Autowired + private UserDetailsService userDetailsService; - /** - * 配置安全过滤器链 - *
- * 配置项: - * 1. 禁用 CSRF(JWT 无状态认证不需要) - * 2. 配置授权规则: - * - /auth/** 接口允许匿名访问(登录、刷新令牌) - * - 其他所有接口需要认证 - * 3. 配置无状态会话管理 - * 4. 添加 JWT 认证过滤器(在 UsernamePasswordAuthenticationFilter 之前) - * - * @param http HttpSecurity 对象 - * @return SecurityFilterChain - * @throws Exception 配置异常 - */ - @Bean - public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { - http - // 禁用 CSRF(JWT 场景下不需要) - .csrf(AbstractHttpConfigurer::disable) + /** + * 配置安全过滤器链 + *
+ * 配置项: + * 1. 禁用 CSRF(JWT 无状态认证不需要) + * 2. 配置授权规则: + * - /auth/** 接口允许匿名访问(登录、刷新令牌) + * - 其他所有接口需要认证 + * 3. 配置无状态会话管理 + * 4. 添加 JWT 认证过滤器(在 UsernamePasswordAuthenticationFilter 之前) + * + * @param http HttpSecurity 对象 + * @return SecurityFilterChain + * @throws Exception 配置异常 + */ + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http + // 禁用 CSRF(JWT 场景下不需要) + .csrf(AbstractHttpConfigurer::disable) - // 配置授权规则 - .authorizeHttpRequests(auth -> auth - // 白名单:允许 /auth/** 接口匿名访问 - .requestMatchers("/auth/**", - "/geetest/**", - "system-settings/public") - .permitAll() + // 配置授权规则 + .authorizeHttpRequests(auth -> auth + // 白名单:允许 /auth/** 接口匿名访问 + .requestMatchers("/auth/**", + "/geetest/**", + "/system-settings/public", + "/static/**") + .permitAll() - // 其他所有接口都需要认证 - .anyRequest().authenticated() - ) + // 其他所有接口都需要认证 + .anyRequest().authenticated() + ) - // 配置无状态会话管理(JWT 无状态认证) - .sessionManagement(session -> session - .sessionCreationPolicy(SessionCreationPolicy.STATELESS) - ) + // 配置无状态会话管理(JWT 无状态认证) + .sessionManagement(session -> session + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) + ) - // 添加 JWT 认证过滤器(在 UsernamePasswordAuthenticationFilter 之前执行) - .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); + // 添加 JWT 认证过滤器(在 UsernamePasswordAuthenticationFilter 之前执行) + .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); - return http.build(); - } + return http.build(); + } - /** - * 密码编码器 Bean - * 使用 BCrypt 算法,强度为 12(2^12 = 4096 次哈希) - *
- * BCrypt 优势: - * - 自动加盐 - * - 计算密集,防暴力破解 - * - 业界标准 - * - * @return PasswordEncoder - */ - @Bean - public PasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(12); - } + /** + * 密码编码器 Bean + * 使用 BCrypt 算法,强度为 12(2^12 = 4096 次哈希) + *
+ * BCrypt 优势: + * - 自动加盐 + * - 计算密集,防暴力破解 + * - 业界标准 + * + * @return PasswordEncoder + */ + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(12); + } - /** - * 认证管理器 Bean - * Spring Security 用于处理认证请求 - * - * @param authenticationConfiguration 认证配置 - * @return AuthenticationManager - * @throws Exception 配置异常 - */ - @Bean - public AuthenticationManager authenticationManager( - AuthenticationConfiguration authenticationConfiguration) throws Exception { - return authenticationConfiguration.getAuthenticationManager(); - } + /** + * 认证管理器 Bean + * Spring Security 用于处理认证请求 + * + * @param authenticationConfiguration 认证配置 + * @return AuthenticationManager + * @throws Exception 配置异常 + */ + @Bean + public AuthenticationManager authenticationManager( + AuthenticationConfiguration authenticationConfiguration) throws Exception { + return authenticationConfiguration.getAuthenticationManager(); + } - /** - * DAO 认证提供者 Bean - * 连接 UserDetailsService 和 PasswordEncoder - *
- * 工作流程: - * 1. 从 UserDetailsService 加载用户信息 - * 2. 使用 PasswordEncoder 验证密码 - * - * @return DaoAuthenticationProvider - */ - @Bean - public DaoAuthenticationProvider authenticationProvider() { - DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(); - authProvider.setUserDetailsService(userDetailsService); - authProvider.setPasswordEncoder(passwordEncoder()); - return authProvider; - } + /** + * DAO 认证提供者 Bean + * 连接 UserDetailsService 和 PasswordEncoder + *
+ * 工作流程:
+ * 1. 从 UserDetailsService 加载用户信息
+ * 2. 使用 PasswordEncoder 验证密码
+ *
+ * @return DaoAuthenticationProvider
+ */
+ @Bean
+ public DaoAuthenticationProvider authenticationProvider() {
+ DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
+ authProvider.setUserDetailsService(userDetailsService);
+ authProvider.setPasswordEncoder(passwordEncoder());
+ return authProvider;
+ }
}
diff --git a/xianyu-server/src/main/java/top/biwin/xinayu/server/controller/AssistController.java b/xianyu-server/src/main/java/top/biwin/xinayu/server/controller/AssistController.java
new file mode 100644
index 0000000..184359e
--- /dev/null
+++ b/xianyu-server/src/main/java/top/biwin/xinayu/server/controller/AssistController.java
@@ -0,0 +1,117 @@
+package top.biwin.xinayu.server.controller;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+import top.biwin.xinayu.common.dto.response.FileUploadResponse;
+import top.biwin.xinayu.server.util.ImageUtils;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.UUID;
+
+/**
+ * 辅助功能控制器
+ * 提供文件上传等辅助接口哦~ (〃^ω^〃)
+ *
+ * @author wangli
+ * @since 2026-01-30 10:46
+ */
+@Slf4j
+@RestController
+public class AssistController {
+
+ @Value("${assistant.static.uploads.images}")
+ private String uploadDir;
+
+ /**
+ * 获取图片内容
+ * 会直接返回处理后的 JPEG 二进制流哦!📸✨
+ *
+ * @param filename 文件名
+ * @return 图片二进制流
+ */
+ @GetMapping(value = "${assistant.static.uploads.images}{filename:.+}", produces = MediaType.IMAGE_JPEG_VALUE)
+ public ResponseEntity