From 7a7247a851353057d421412d65f8e02c3a21f78d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E5=AD=9F?= <3111696955@qq.com> Date: Fri, 1 Aug 2025 08:58:41 +0800 Subject: [PATCH] =?UTF-8?q?feat(security):=20=E6=B7=BB=E5=8A=A0=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E8=AE=A4=E8=AF=81=E5=92=8C=E6=8E=88=E6=9D=83?= =?UTF-8?q?=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 - 新增 JwtAccessDeniedHandler 处理权限不足异常 - 新增 JwtAuthenticationEntryPoint 处理认证失败异常- 在 SecurityConfig 中集成自定义异常处理器 - 优化 GlobalExceptionHandler 中的异常日志输出 --- .../common/advice/GlobalExceptionHandler.java | 15 ++++++-- .../bijihoudaun/config/SecurityConfig.java | 17 +++++++-- .../security/JwtAccessDeniedHandler.java | 35 ++++++++++++++++++ .../security/JwtAuthenticationEntryPoint.java | 37 +++++++++++++++++++ 4 files changed, 97 insertions(+), 7 deletions(-) create mode 100644 biji-houdaun/src/main/java/com/test/bijihoudaun/config/security/JwtAccessDeniedHandler.java create mode 100644 biji-houdaun/src/main/java/com/test/bijihoudaun/config/security/JwtAuthenticationEntryPoint.java diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/common/advice/GlobalExceptionHandler.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/common/advice/GlobalExceptionHandler.java index 0674ab7..d8e99fa 100644 --- a/biji-houdaun/src/main/java/com/test/bijihoudaun/common/advice/GlobalExceptionHandler.java +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/common/advice/GlobalExceptionHandler.java @@ -69,11 +69,20 @@ public class GlobalExceptionHandler { } /** - * 处理其他异常 + * 处理请求体格式错误异常 (例如JSON格式错误) + */ + @ExceptionHandler(org.springframework.http.converter.HttpMessageNotReadableException.class) + public R handleHttpMessageNotReadableException(org.springframework.http.converter.HttpMessageNotReadableException e) { + log.error("请求参数格式不正确: {}", e.getMessage()); + return R.fail(ResultCode.VALIDATE_FAILED.getCode(), "请求参数格式不正确"); + } + + /** + * 处理其他所有未捕获的异常 */ @ExceptionHandler(Exception.class) public R handleException(Exception e) { - log.error("系统异常:{}", e.getMessage()); - return R.fail(ResultCode.FAILED.getCode(), "系统繁忙,请稍后再试:" + e.getMessage()); + log.error("系统异常:", e); // 打印完整的堆栈信息 + return R.fail(ResultCode.FAILED.getCode(), "系统繁忙,请稍后再试"); } } diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/config/SecurityConfig.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/config/SecurityConfig.java index e0d17c8..78538ae 100644 --- a/biji-houdaun/src/main/java/com/test/bijihoudaun/config/SecurityConfig.java +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/config/SecurityConfig.java @@ -1,9 +1,7 @@ package com.test.bijihoudaun.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 com.test.bijihoudaun.config.security.JwtAccessDeniedHandler; +import com.test.bijihoudaun.config.security.JwtAuthenticationEntryPoint; import com.test.bijihoudaun.interceptor.JwtAuthenticationTokenFilter; import com.test.bijihoudaun.util.JwtTokenUtil; import org.springframework.beans.factory.annotation.Autowired; @@ -29,6 +27,12 @@ public class SecurityConfig { @Autowired private JwtTokenUtil jwtTokenUtil; + @Autowired + private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; + + @Autowired + private JwtAccessDeniedHandler jwtAccessDeniedHandler; + @Value("${jwt.header}") private String tokenHeader; @@ -51,6 +55,11 @@ public class SecurityConfig { .requestMatchers("/doc.html", "/webjars/**", "/v3/api-docs/**", "/api/user/login", "/api/user/register").permitAll() .requestMatchers(org.springframework.http.HttpMethod.GET).permitAll() .anyRequest().authenticated() + ) + // 添加自定义的异常处理器 + .exceptionHandling(exceptions -> exceptions + .authenticationEntryPoint(jwtAuthenticationEntryPoint) + .accessDeniedHandler(jwtAccessDeniedHandler) ); // 在这里添加JWT过滤器 diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/config/security/JwtAccessDeniedHandler.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/config/security/JwtAccessDeniedHandler.java new file mode 100644 index 0000000..ca436ef --- /dev/null +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/config/security/JwtAccessDeniedHandler.java @@ -0,0 +1,35 @@ +package com.test.bijihoudaun.config.security; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.test.bijihoudaun.common.response.R; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.stereotype.Component; + + +import java.io.IOException; + +/** + * 自定义授权失败处理器 + * 当认证成功的用户尝试访问其没有权限的资源时,此处理器被调用。 + */ +@Component +public class JwtAccessDeniedHandler implements AccessDeniedHandler { + + @Override + public void handle(HttpServletRequest request, + HttpServletResponse response, + AccessDeniedException accessDeniedException) throws IOException, ServletException { + response.setCharacterEncoding("UTF-8"); + response.setContentType("application/json"); + response.setStatus(HttpServletResponse.SC_FORBIDDEN); // 403 + + R result = R.fail("权限不足,无法访问此资源"); + + ObjectMapper objectMapper = new ObjectMapper(); + response.getWriter().write(objectMapper.writeValueAsString(result)); + } +} \ No newline at end of file diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/config/security/JwtAuthenticationEntryPoint.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/config/security/JwtAuthenticationEntryPoint.java new file mode 100644 index 0000000..5ca8d57 --- /dev/null +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/config/security/JwtAuthenticationEntryPoint.java @@ -0,0 +1,37 @@ +package com.test.bijihoudaun.config.security; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.test.bijihoudaun.common.response.R; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + + +import java.io.IOException; + +/** + * 自定义认证失败处理器 + * 当用户尝试访问受保护的资源而未提供有效凭证时(例如token无效或过期),此处理器被调用。 + */ +@Component +public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { + + @Override + public void commence(HttpServletRequest request, + HttpServletResponse response, + AuthenticationException authException) throws IOException, ServletException { + response.setCharacterEncoding("UTF-8"); + response.setContentType("application/json"); + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 401 + + // 创建一个包含中文错误信息的R对象 + R result = R.fail("认证失败,请重新登录"); + + // 使用ObjectMapper将对象转换为JSON字符串并写入响应 + ObjectMapper objectMapper = new ObjectMapper(); + response.getWriter().write(objectMapper.writeValueAsString(result)); + } +} \ No newline at end of file