From 2474168344d2bd77ba8ae42be91e4d724b16f3f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A2=A8=E6=82=B2=E4=B8=9D=E6=9F=93?= <1703373975@qq.com> Date: Tue, 16 Sep 2025 14:54:19 +0800 Subject: [PATCH] =?UTF-8?q?add:=E5=8A=9F=E8=83=BD=E7=A7=BB=E6=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user-adapter-in-web/pom.xml | 6 + .../in/web/controller/UserController.java | 14 +- user-service/user-service-bootstrap/pom.xml | 16 ++ .../bootstrap/config/Knife4jConfig.java | 23 +++ .../bootstrap/config/SecurityConfig.java | 55 ++++++ .../config/SecurityExceptionHandler.java | 47 +++++ .../src/main/resources/application.properties | 8 + .../src/main/resources/static/index.html | 163 ++++++++++++++++++ 8 files changed, 330 insertions(+), 2 deletions(-) create mode 100644 user-service/user-service-bootstrap/src/main/java/com/example/user/service/bootstrap/config/Knife4jConfig.java create mode 100644 user-service/user-service-bootstrap/src/main/java/com/example/user/service/bootstrap/config/SecurityConfig.java create mode 100644 user-service/user-service-bootstrap/src/main/java/com/example/user/service/bootstrap/config/SecurityExceptionHandler.java create mode 100644 user-service/user-service-bootstrap/src/main/resources/static/index.html diff --git a/user-service/user-service-adapter/user-adapter-in/user-adapter-in-web/pom.xml b/user-service/user-service-adapter/user-adapter-in/user-adapter-in-web/pom.xml index b673bee..0142671 100644 --- a/user-service/user-service-adapter/user-adapter-in/user-adapter-in-web/pom.xml +++ b/user-service/user-service-adapter/user-adapter-in/user-adapter-in-web/pom.xml @@ -25,6 +25,12 @@ spring-boot-starter-test test + + + org.springframework.security + spring-security-test + test + org.projectlombok lombok diff --git a/user-service/user-service-adapter/user-adapter-in/user-adapter-in-web/src/main/java/com/example/user/adapter/in/web/controller/UserController.java b/user-service/user-service-adapter/user-adapter-in/user-adapter-in-web/src/main/java/com/example/user/adapter/in/web/controller/UserController.java index 96820c0..abd2bec 100644 --- a/user-service/user-service-adapter/user-adapter-in/user-adapter-in-web/src/main/java/com/example/user/adapter/in/web/controller/UserController.java +++ b/user-service/user-service-adapter/user-adapter-in/user-adapter-in-web/src/main/java/com/example/user/adapter/in/web/controller/UserController.java @@ -9,6 +9,9 @@ import com.example.user.service.application.command.UpdateUserCommand; import com.example.user.service.application.command.UserLoginCommand; import com.example.user.service.application.port.in.*; import com.example.user.service.domain.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; @@ -19,6 +22,7 @@ import java.util.List; @RequestMapping("/users") @RestController @RequiredArgsConstructor +@Tag(name = "用户管理", description = "用户相关的API接口") public class UserController { private final GetUserListUseCase getUserListUseCase; @@ -30,6 +34,7 @@ public class UserController { @PostMapping("login") + @Operation(summary = "用户登录", description = "使用用户名和密码进行登录") public String login(@RequestBody UserLoginRequestDTO userLoginRequestDTO){ log.info("UserLoginRequestDTO:{}",userLoginRequestDTO); UserLoginCommand command=UserLoginCommand.builder() @@ -43,6 +48,7 @@ public class UserController { @GetMapping("") + @Operation(summary = "获取所有用户", description = "获取系统中所有用户的列表") public List getUsers() { log.info("getUsers"); return getUserListUseCase.getUsers(); @@ -57,6 +63,7 @@ public class UserController { * @throws IllegalArgumentException 当密码与确认密码不匹配时抛出此异常 */ @PostMapping() + @Operation(summary = "创建新用户", description = "创建一个新的用户账户") public User createUser(@RequestBody CreateUserRequestDTO createUserRequestDTO){ if (!createUserRequestDTO.isPasswordValid()) { @@ -74,13 +81,15 @@ public class UserController { @DeleteMapping("{id}") - public String deleteUser(@PathVariable("id") Long id){ + @Operation(summary = "删除用户", description = "根据用户ID删除用户") + public String deleteUser(@Parameter(description = "用户ID") @PathVariable("id") Long id){ deleteUserUseCase.deleteUser(id); return "success"; } @PutMapping("") + @Operation(summary = "更新用户信息", description = "更新用户的基本信息") public User updateUser(@RequestBody UpdateUserRequestDTO updateUserRequestDTO){ UpdateUserCommand command=UpdateUserCommand.builder() .id(updateUserRequestDTO.id()) @@ -95,7 +104,8 @@ public class UserController { @GetMapping("{id}") - public UserResponseDTO getUserById(@PathVariable("id") Long id){ + @Operation(summary = "根据ID获取用户", description = "根据用户ID获取用户详细信息") + public UserResponseDTO getUserById(@Parameter(description = "用户ID") @PathVariable("id") Long id){ User user = getUserByIdUseCase.getUserById(id); UserResponseDTO userResponseDTO = new UserResponseDTO( user.getId().id(), diff --git a/user-service/user-service-bootstrap/pom.xml b/user-service/user-service-bootstrap/pom.xml index b9c3d17..2725821 100644 --- a/user-service/user-service-bootstrap/pom.xml +++ b/user-service/user-service-bootstrap/pom.xml @@ -48,6 +48,22 @@ spring-cloud-starter-alibaba-nacos-discovery + + org.springframework.boot + spring-boot-starter-security + + + + com.mysql + mysql-connector-j + runtime + + + + com.baomidou + mybatis-plus-spring-boot3-starter + + diff --git a/user-service/user-service-bootstrap/src/main/java/com/example/user/service/bootstrap/config/Knife4jConfig.java b/user-service/user-service-bootstrap/src/main/java/com/example/user/service/bootstrap/config/Knife4jConfig.java new file mode 100644 index 0000000..0282432 --- /dev/null +++ b/user-service/user-service-bootstrap/src/main/java/com/example/user/service/bootstrap/config/Knife4jConfig.java @@ -0,0 +1,23 @@ +package com.example.user.service.bootstrap.config; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.Contact; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class Knife4jConfig { + + @Bean + public OpenAPI customOpenAPI() { + return new OpenAPI() + .info(new Info() + .title("User Service API") + .version("1.0.0") + .description("User Service API Documentation with Spring Security") + .contact(new Contact() + .name("User Service Team") + .email("support@example.com"))); + } +} diff --git a/user-service/user-service-bootstrap/src/main/java/com/example/user/service/bootstrap/config/SecurityConfig.java b/user-service/user-service-bootstrap/src/main/java/com/example/user/service/bootstrap/config/SecurityConfig.java new file mode 100644 index 0000000..e51e2cb --- /dev/null +++ b/user-service/user-service-bootstrap/src/main/java/com/example/user/service/bootstrap/config/SecurityConfig.java @@ -0,0 +1,55 @@ +package com.example.user.service.bootstrap.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; +import org.springframework.security.web.SecurityFilterChain; + +@Configuration +@EnableWebSecurity +public class SecurityConfig { + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http + .authorizeHttpRequests(authz -> authz + .requestMatchers("/", "/index.html", "/css/**", "/js/**", "/images/**").permitAll() + .requestMatchers("/users/login").permitAll() + .requestMatchers("/doc.html", "/v3/api-docs/**", "/swagger-ui/**", "/webjars/**").permitAll() + .anyRequest().authenticated() + ) + .csrf(csrf -> csrf.disable()) + .formLogin(form -> form + .loginPage("/") + .permitAll() + ) + .httpBasic(httpBasic -> {}); + + return http.build(); + } + + @Bean + public UserDetailsService userDetailsService(){ + + UserDetails admin = User.builder() + .username("admin") + .password(passwordEncoder().encode("admin")) + .roles("ADMIN") + .build(); + + return new InMemoryUserDetailsManager(admin); + } + + @Bean + public PasswordEncoder passwordEncoder(){ + return new BCryptPasswordEncoder(); + } + +} diff --git a/user-service/user-service-bootstrap/src/main/java/com/example/user/service/bootstrap/config/SecurityExceptionHandler.java b/user-service/user-service-bootstrap/src/main/java/com/example/user/service/bootstrap/config/SecurityExceptionHandler.java new file mode 100644 index 0000000..7558710 --- /dev/null +++ b/user-service/user-service-bootstrap/src/main/java/com/example/user/service/bootstrap/config/SecurityExceptionHandler.java @@ -0,0 +1,47 @@ +package com.example.user.service.bootstrap.config; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@RestControllerAdvice +public class SecurityExceptionHandler { + + @ExceptionHandler(BadCredentialsException.class) + public ResponseEntity> handleBadCredentials(BadCredentialsException e) { + log.error("Bad credentials: {}", e.getMessage()); + Map response = new HashMap<>(); + response.put("error", "认证失败"); + response.put("message", "用户名或密码错误"); + response.put("status", HttpStatus.UNAUTHORIZED.value()); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response); + } + + @ExceptionHandler(AccessDeniedException.class) + public ResponseEntity> handleAccessDenied(AccessDeniedException e) { + log.error("Access denied: {}", e.getMessage()); + Map response = new HashMap<>(); + response.put("error", "访问被拒绝"); + response.put("message", "您没有权限访问此资源"); + response.put("status", HttpStatus.FORBIDDEN.value()); + return ResponseEntity.status(HttpStatus.FORBIDDEN).body(response); + } + + @ExceptionHandler(IllegalArgumentException.class) + public ResponseEntity> handleIllegalArgument(IllegalArgumentException e) { + log.error("Illegal argument: {}", e.getMessage()); + Map response = new HashMap<>(); + response.put("error", "参数错误"); + response.put("message", e.getMessage()); + response.put("status", HttpStatus.BAD_REQUEST.value()); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); + } +} diff --git a/user-service/user-service-bootstrap/src/main/resources/application.properties b/user-service/user-service-bootstrap/src/main/resources/application.properties index 3ffae5b..1204a8d 100644 --- a/user-service/user-service-bootstrap/src/main/resources/application.properties +++ b/user-service/user-service-bootstrap/src/main/resources/application.properties @@ -2,6 +2,14 @@ server.port=28080 spring.application.name=user-service +# 数据库连接配置 +spring.datasource.url=jdbc:mysql://192.168.168.128:3306/user_service?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&allowMultiQueries=true&useSSL=false&allowPublicKeyRetrieval=true&tinyInt1isBit=false +spring.datasource.username=root +spring.datasource.password=root +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver + +mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl + # Nacos认证信息 diff --git a/user-service/user-service-bootstrap/src/main/resources/static/index.html b/user-service/user-service-bootstrap/src/main/resources/static/index.html new file mode 100644 index 0000000..ea21a9b --- /dev/null +++ b/user-service/user-service-bootstrap/src/main/resources/static/index.html @@ -0,0 +1,163 @@ + + + + + + User Service + + + +
+

User Service - Spring Security Demo

+ + + +
+

可用的 API 接口

+
    +
  • POST/users/login - 用户登录
  • +
  • GET/users - 获取所有用户
  • +
  • POST/users - 创建新用户
  • +
  • GET/users/{id} - 根据ID获取用户
  • +
  • PUT/users - 更新用户信息
  • +
  • DELETE/users/{id} - 删除用户
  • +
+ +

Knife4j API 文档

+

访问 /doc.html 查看完整的 API 文档

+
+
+ + + + -- Gitee