feat(security): 添加自定义认证和授权异常处理器
- 新增 JwtAccessDeniedHandler 处理权限不足异常 - 新增 JwtAuthenticationEntryPoint 处理认证失败异常- 在 SecurityConfig 中集成自定义异常处理器 - 优化 GlobalExceptionHandler 中的异常日志输出
This commit is contained in:
@@ -69,11 +69,20 @@ public class GlobalExceptionHandler {
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理其他异常
|
||||
* 处理请求体格式错误异常 (例如JSON格式错误)
|
||||
*/
|
||||
@ExceptionHandler(org.springframework.http.converter.HttpMessageNotReadableException.class)
|
||||
public R<String> handleHttpMessageNotReadableException(org.springframework.http.converter.HttpMessageNotReadableException e) {
|
||||
log.error("请求参数格式不正确: {}", e.getMessage());
|
||||
return R.fail(ResultCode.VALIDATE_FAILED.getCode(), "请求参数格式不正确");
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理其他所有未捕获的异常
|
||||
*/
|
||||
@ExceptionHandler(Exception.class)
|
||||
public R<Void> handleException(Exception e) {
|
||||
log.error("系统异常:{}", e.getMessage());
|
||||
return R.fail(ResultCode.FAILED.getCode(), "系统繁忙,请稍后再试:" + e.getMessage());
|
||||
log.error("系统异常:", e); // 打印完整的堆栈信息
|
||||
return R.fail(ResultCode.FAILED.getCode(), "系统繁忙,请稍后再试");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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过滤器
|
||||
|
||||
@@ -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<String> result = R.fail("权限不足,无法访问此资源");
|
||||
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
response.getWriter().write(objectMapper.writeValueAsString(result));
|
||||
}
|
||||
}
|
||||
@@ -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<String> result = R.fail("认证失败,请重新登录");
|
||||
|
||||
// 使用ObjectMapper将对象转换为JSON字符串并写入响应
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
response.getWriter().write(objectMapper.writeValueAsString(result));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user