From 7fa1a38e3370f714afdae1aefadf295db2be1891 Mon Sep 17 00:00:00 2001 From: yulinling <2712495353@qq.com> Date: Thu, 19 Jun 2025 21:53:33 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20-=20=E5=AE=8C=E5=96=84=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=E5=8A=9F=E8=83=BD=20-=20=E5=AE=8C=E5=96=84=E5=85=A8?= =?UTF-8?q?=E5=B1=80=E5=BC=82=E5=B8=B8=E5=A4=84=E7=90=86=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/config/SecurityConfig.java | 4 +- .../workflow/controller/AuthController.java | 18 ++++- .../workflow/dto/request/RegisterRequest.java | 65 +++++++++++++++++++ .../handler/GlobalExceptionHandler.java | 9 ++- .../yulinling/workflow/model/ApiResponse.java | 4 +- .../security/JwtAuthenticationEntryPoint.java | 4 ++ .../workflow/service/AuthService.java | 7 ++ .../service/impl/AuthServiceImpl.java | 65 ++++++++++++++++++- src/main/resources/db/schema.sql | 22 +++---- 9 files changed, 177 insertions(+), 21 deletions(-) create mode 100644 src/main/java/asia/yulinling/workflow/dto/request/RegisterRequest.java diff --git a/src/main/java/asia/yulinling/workflow/config/SecurityConfig.java b/src/main/java/asia/yulinling/workflow/config/SecurityConfig.java index 745b40b..5c7dda0 100644 --- a/src/main/java/asia/yulinling/workflow/config/SecurityConfig.java +++ b/src/main/java/asia/yulinling/workflow/config/SecurityConfig.java @@ -56,8 +56,8 @@ public class SecurityConfig { ) // 认证请求 .authorizeHttpRequests(auth -> auth - .requestMatchers("/login").permitAll() -// .requestMatchers("/users", "/users/**").hasRole("ADMIN") + .requestMatchers("/auth/**").permitAll() + .requestMatchers("/auth/register").permitAll() .anyRequest().access((authenticationSupplier, requestAuthorizationContext) -> { HttpServletRequest request = requestAuthorizationContext.getRequest(); Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); diff --git a/src/main/java/asia/yulinling/workflow/controller/AuthController.java b/src/main/java/asia/yulinling/workflow/controller/AuthController.java index 5f60ae0..6698f9d 100644 --- a/src/main/java/asia/yulinling/workflow/controller/AuthController.java +++ b/src/main/java/asia/yulinling/workflow/controller/AuthController.java @@ -1,15 +1,18 @@ package asia.yulinling.workflow.controller; import asia.yulinling.workflow.dto.request.LoginRequest; +import asia.yulinling.workflow.dto.request.RegisterRequest; import asia.yulinling.workflow.dto.response.JWTAuthResponse; import asia.yulinling.workflow.model.ApiResponse; import asia.yulinling.workflow.service.AuthService; import asia.yulinling.workflow.utils.ResponseUtil; +import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** @@ -22,16 +25,27 @@ import org.springframework.web.bind.annotation.RestController; */ @RestController @RequiredArgsConstructor +@RequestMapping("/auth") @Slf4j public class AuthController { - private final AuthService authenticate; + private final AuthService authService; @PostMapping("/login") public ApiResponse login(@RequestBody LoginRequest loginRequest) { - String token = authenticate.login(loginRequest); + String token = authService.login(loginRequest); JWTAuthResponse jwtAuthResponse = new JWTAuthResponse(token); return ApiResponse.ofSuccess(jwtAuthResponse); } + + @PostMapping("/logout") + public ApiResponse logout(HttpServletRequest request) throws SecurityException { + return authService.logout(request); + } + + @PostMapping("/register") + public ApiResponse register(@RequestBody RegisterRequest registerRequest) throws Exception { + return authService.register(registerRequest); + } } diff --git a/src/main/java/asia/yulinling/workflow/dto/request/RegisterRequest.java b/src/main/java/asia/yulinling/workflow/dto/request/RegisterRequest.java new file mode 100644 index 0000000..0adcb5c --- /dev/null +++ b/src/main/java/asia/yulinling/workflow/dto/request/RegisterRequest.java @@ -0,0 +1,65 @@ +package asia.yulinling.workflow.dto.request; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +/** + *

+ * 注册请求类 + *

+ * + * @author YLL + * @since 2025/6/19 + */ +@Data +public class RegisterRequest { + + /** + * 用户名 + */ + @NotBlank(message = "用户名不能为空") + private String username; + + /** + * 昵称 + */ + private String nickname; + + /** + * 密码 + */ + @NotBlank(message = "密码不能为空") + private String password; + + /** + * 二次密码 + */ + @NotBlank(message = "确认密码不能为空") + private String confirmPassword; + + /** + * 电子邮箱 + */ + @Email + private String email; + + /** + * 生日 + */ + private String birthday; + + /** + * 性别 + */ + private Integer sex; + + /** + * 手机号 + */ + @Max(11) + @Min(5) + private String phone; +} diff --git a/src/main/java/asia/yulinling/workflow/exception/handler/GlobalExceptionHandler.java b/src/main/java/asia/yulinling/workflow/exception/handler/GlobalExceptionHandler.java index f43769d..ec146b3 100644 --- a/src/main/java/asia/yulinling/workflow/exception/handler/GlobalExceptionHandler.java +++ b/src/main/java/asia/yulinling/workflow/exception/handler/GlobalExceptionHandler.java @@ -1,9 +1,12 @@ package asia.yulinling.workflow.exception.handler; +import asia.yulinling.workflow.exception.BaseException; import asia.yulinling.workflow.exception.JsonException; import asia.yulinling.workflow.exception.PageException; import asia.yulinling.workflow.model.ApiResponse; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; @@ -30,9 +33,9 @@ public class GlobalExceptionHandler { */ @ExceptionHandler(Exception.class) @ResponseBody - public ApiResponse jsonErrorHandler(JsonException e) { - log.error(e.getMessage()); - return ApiResponse.ofException(e); + public ApiResponse cathAllErrorHandler(Exception e) { + log.error("json error:{}", e.getMessage()); + return ApiResponse.of(500, e.getMessage(), null); } /** diff --git a/src/main/java/asia/yulinling/workflow/model/ApiResponse.java b/src/main/java/asia/yulinling/workflow/model/ApiResponse.java index 074dd24..d2c03ce 100644 --- a/src/main/java/asia/yulinling/workflow/model/ApiResponse.java +++ b/src/main/java/asia/yulinling/workflow/model/ApiResponse.java @@ -56,7 +56,7 @@ public class ApiResponse { * @param data 返回数据 * @return ApiResponse */ - public static ApiResponse of(Integer code, String message, T data) { + public static ApiResponse of(Integer code, String message, Object data) { return new ApiResponse<>(code, message, data); } @@ -109,7 +109,7 @@ public class ApiResponse { * @param {@link BaseException} 子类 * @return ApiResponse */ - public static ApiResponse ofException(T t, T data) { + public static ApiResponse ofException(T t, Object data) { return of(t.getCode(), t.getMessage(), data); } diff --git a/src/main/java/asia/yulinling/workflow/security/JwtAuthenticationEntryPoint.java b/src/main/java/asia/yulinling/workflow/security/JwtAuthenticationEntryPoint.java index 9f9063a..f834e1f 100644 --- a/src/main/java/asia/yulinling/workflow/security/JwtAuthenticationEntryPoint.java +++ b/src/main/java/asia/yulinling/workflow/security/JwtAuthenticationEntryPoint.java @@ -5,6 +5,7 @@ import asia.yulinling.workflow.model.ApiResponse; import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.stereotype.Component; @@ -20,6 +21,7 @@ import java.io.IOException; * @since 2025/6/13 */ @Component +@Slf4j public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { private final ObjectMapper objectMapper; @@ -31,6 +33,8 @@ public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { + log.error("AuthenticationException: {}",authException.getMessage()); + // 1. 设置res 401 response.setContentType("application/json;charset=UTF-8"); response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); diff --git a/src/main/java/asia/yulinling/workflow/service/AuthService.java b/src/main/java/asia/yulinling/workflow/service/AuthService.java index 7293440..a4e5570 100644 --- a/src/main/java/asia/yulinling/workflow/service/AuthService.java +++ b/src/main/java/asia/yulinling/workflow/service/AuthService.java @@ -1,6 +1,9 @@ package asia.yulinling.workflow.service; import asia.yulinling.workflow.dto.request.LoginRequest; +import asia.yulinling.workflow.dto.request.RegisterRequest; +import asia.yulinling.workflow.model.ApiResponse; +import jakarta.servlet.http.HttpServletRequest; /** *

@@ -12,4 +15,8 @@ import asia.yulinling.workflow.dto.request.LoginRequest; */ public interface AuthService { String login(LoginRequest loginRequest); + + ApiResponse logout(HttpServletRequest request) throws SecurityException; + + ApiResponse register(RegisterRequest request) throws Exception; } diff --git a/src/main/java/asia/yulinling/workflow/service/impl/AuthServiceImpl.java b/src/main/java/asia/yulinling/workflow/service/impl/AuthServiceImpl.java index dc894a6..0f4c5d0 100644 --- a/src/main/java/asia/yulinling/workflow/service/impl/AuthServiceImpl.java +++ b/src/main/java/asia/yulinling/workflow/service/impl/AuthServiceImpl.java @@ -1,15 +1,29 @@ package asia.yulinling.workflow.service.impl; +import asia.yulinling.workflow.constant.Status; import asia.yulinling.workflow.dto.request.LoginRequest; +import asia.yulinling.workflow.dto.request.RegisterRequest; +import asia.yulinling.workflow.mapper.UserMapper; +import asia.yulinling.workflow.model.ApiResponse; +import asia.yulinling.workflow.model.entity.User; import asia.yulinling.workflow.service.AuthService; import asia.yulinling.workflow.utils.JwtUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; +import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper; +import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.RequestBody; + +import java.util.Date; /** *

@@ -26,6 +40,8 @@ public class AuthServiceImpl implements AuthService { private final AuthenticationManager authenticationManager; private final JwtUtil jwtUtil; + private final PasswordEncoder passwordEncoder; + private final UserMapper userMapper; @Override public String login(LoginRequest loginRequest) { @@ -33,8 +49,55 @@ public class AuthServiceImpl implements AuthService { loginRequest.getUsername(), loginRequest.getPassword() )); SecurityContextHolder.getContext().setAuthentication(authentication); - String token =jwtUtil.generateToken(authentication, false); + String token = jwtUtil.generateToken(authentication, false); log.info("generateToken: {}", token); return token; } + + @Override + public ApiResponse logout(HttpServletRequest request) throws SecurityException { + try { + jwtUtil.invalidateToken(request); + } catch (SecurityException e) { + log.info("invalidateToken: {}", e.getMessage()); + } + return ApiResponse.ofStatus(Status.LOGOUT); + } + + @Override + public ApiResponse register(RegisterRequest request) throws Exception { + + if (!StrUtil.equals(request.getConfirmPassword(), request.getPassword())) { + log.info("password {}, confirmPassword {}", request.getConfirmPassword(), request.getPassword()); + return ApiResponse.of(400, "密码不一致", null); + } + + if (userMapper.exists(new LambdaQueryWrapper().eq(User::getUsername, request.getUsername()))) { + return ApiResponse.of(400, "用户名已存在", null); + } + + if (userMapper.exists(new LambdaQueryWrapper().eq(User::getEmail, request.getEmail()))) { + return ApiResponse.of(400, "邮箱已注册", null); + } + + User user = new User(); + user.setUsername(request.getUsername()); + user.setPassword(passwordEncoder.encode(request.getPassword())); + user.setEmail(request.getEmail()); + user.setNickname(request.getNickname()); + user.setPhone(request.getPhone()); + user.setBirthday(request.getBirthday()); + user.setStatus(1); + user.setUpdateTime(new Date()); + + log.info("User: {}", user); + try { + userMapper.insert(user); + } catch (Exception e) { + log.error("insertUser Error: {}", e.getMessage()); + throw new RuntimeException(e); + } + + return ApiResponse.of(200, "注册成功", null); + } } diff --git a/src/main/resources/db/schema.sql b/src/main/resources/db/schema.sql index f6c27cc..6fbe4b6 100644 --- a/src/main/resources/db/schema.sql +++ b/src/main/resources/db/schema.sql @@ -1,18 +1,18 @@ DROP TABLE IF EXISTS `wk_user`; CREATE TABLE `wk_user` ( - `id` bigint(64) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '主键', - `username` VARCHAR(32) NOT NULL UNIQUE COMMENT '用户名', - `nickname` VARCHAR(32) NOT NULL UNIQUE COMMENT '昵称', + `id` bigint(64) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '主键', + `username` VARCHAR(32) NOT NULL UNIQUE COMMENT '用户名', + `nickname` VARCHAR(32) DEFAULT '默认用户' COMMENT '昵称', `password` VARCHAR(256) NOT NULL COMMENT '加密后的密码', - `email` VARCHAR(32) NOT NULL UNIQUE COMMENT '邮箱', - `birthday` DATETIME DEFAULT NULL COMMENT '生日', - `sex` INT(2) DEFAULT NULL COMMENT '性别,男-1,女-2', - `phone` VARCHAR(15) DEFAULT NULL UNIQUE COMMENT '手机号', - `status` INT(2) NOT NULL DEFAULT 1 COMMENT '状态 -1:删除 0:警用 1:启用', - `create_time` DATETIME NOT NULL DEFAULT NOW() COMMENT '创建时间', - `update_time` DATETIME NOT NULL DEFAULT NOW() COMMENT '上次更新时间', - `last_login_time` DATETIME DEFAULT NULL COMMENT '上次登录时间' + `email` VARCHAR(32) UNIQUE COMMENT '邮箱', + `birthday` DATETIME DEFAULT NULL COMMENT '生日', + `sex` INT(2) DEFAULT NULL COMMENT '性别,男-1,女-2', + `phone` VARCHAR(15) DEFAULT NULL UNIQUE COMMENT '手机号', + `status` INT(2) NOT NULL DEFAULT 1 COMMENT '状态 -1:删除 0:警用 1:启用', + `create_time` DATETIME NOT NULL DEFAULT NOW() COMMENT '创建时间', + `update_time` DATETIME NOT NULL DEFAULT NOW() COMMENT '上次更新时间', + `last_login_time` DATETIME DEFAULT NULL COMMENT '上次登录时间' ) ENGINE = INNODB DEFAULT CHARSET = UTF8 COMMENT '用户表';