mirror of
https://github.com/FatttSnake/Pinnacle-OA.git
synced 2026-04-05 23:11:24 +08:00
Optimized exception interceptor
This commit is contained in:
@@ -0,0 +1,18 @@
|
|||||||
|
package com.cfive.pinnacle.config;
|
||||||
|
|
||||||
|
import com.cfive.pinnacle.filter.ExceptionFilter;
|
||||||
|
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class FilterConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public FilterRegistrationBean<ExceptionFilter> exceptionFilterFilterRegistrationBean(ExceptionFilter exceptionFilter) {
|
||||||
|
FilterRegistrationBean<ExceptionFilter> registrationBean = new FilterRegistrationBean<>(exceptionFilter);
|
||||||
|
registrationBean.setName("exceptionFilter");
|
||||||
|
registrationBean.setOrder(-100);
|
||||||
|
return registrationBean;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -83,7 +83,7 @@ public class SecurityConfig {
|
|||||||
|
|
||||||
// Allow anonymous access
|
// Allow anonymous access
|
||||||
.authorizeHttpRequests()
|
.authorizeHttpRequests()
|
||||||
.requestMatchers("/login", "/doc.html", "/swagger-ui/**", "/webjars/**", "/v3/**", "/swagger-ui.html")
|
.requestMatchers("/login", "/error/thrown", "/doc.html", "/swagger-ui/**", "/webjars/**", "/v3/**", "/swagger-ui.html")
|
||||||
.anonymous()
|
.anonymous()
|
||||||
|
|
||||||
// Authentication required
|
// Authentication required
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.cfive.pinnacle.controller;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/error")
|
||||||
|
public class ExceptionController {
|
||||||
|
@RequestMapping("/thrown")
|
||||||
|
public void thrown(HttpServletRequest request) {
|
||||||
|
throw (RuntimeException) request.getAttribute("filter.error");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.cfive.pinnacle.exception;
|
||||||
|
|
||||||
|
public class TokenHasExpiredException extends RuntimeException {
|
||||||
|
public TokenHasExpiredException() {
|
||||||
|
super("Token has expired");
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenHasExpiredException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenHasExpiredException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenHasExpiredException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenHasExpiredException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||||
|
super(message, cause, enableSuppression, writableStackTrace);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.cfive.pinnacle.filter;
|
||||||
|
|
||||||
|
import jakarta.servlet.*;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class ExceptionFilter implements Filter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(FilterConfig filterConfig) throws ServletException {
|
||||||
|
Filter.super.init(filterConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
|
||||||
|
try {
|
||||||
|
filterChain.doFilter(servletRequest, servletResponse);
|
||||||
|
} catch (Exception e) {
|
||||||
|
servletRequest.setAttribute("filter.error", e);
|
||||||
|
servletRequest.getRequestDispatcher("/error/thrown").forward(servletRequest, servletResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
Filter.super.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
package com.cfive.pinnacle.filter;
|
package com.cfive.pinnacle.filter;
|
||||||
|
|
||||||
import com.cfive.pinnacle.entity.common.ResponseCode;
|
|
||||||
import com.cfive.pinnacle.entity.permission.LoginUser;
|
import com.cfive.pinnacle.entity.permission.LoginUser;
|
||||||
|
import com.cfive.pinnacle.exception.TokenHasExpiredException;
|
||||||
import com.cfive.pinnacle.utils.JwtUtil;
|
import com.cfive.pinnacle.utils.JwtUtil;
|
||||||
import com.cfive.pinnacle.utils.RedisCache;
|
import com.cfive.pinnacle.utils.RedisCache;
|
||||||
import com.cfive.pinnacle.utils.WebUtil;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import jakarta.annotation.Nonnull;
|
import jakarta.annotation.Nonnull;
|
||||||
import jakarta.servlet.FilterChain;
|
import jakarta.servlet.FilterChain;
|
||||||
@@ -33,25 +32,18 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
|
|||||||
@Override
|
@Override
|
||||||
protected void doFilterInternal(HttpServletRequest request, @Nonnull HttpServletResponse response, @Nonnull FilterChain filterChain) throws ServletException, IOException {
|
protected void doFilterInternal(HttpServletRequest request, @Nonnull HttpServletResponse response, @Nonnull FilterChain filterChain) throws ServletException, IOException {
|
||||||
String token = request.getHeader("token");
|
String token = request.getHeader("token");
|
||||||
if (!StringUtils.hasText(token)) {
|
|
||||||
|
if (!StringUtils.hasText(token) || "/error/thrown".equals(request.getServletPath())) {
|
||||||
filterChain.doFilter(request, response);
|
filterChain.doFilter(request, response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
JwtUtil.parseJWT(token);
|
||||||
JwtUtil.parseJWT(token);
|
|
||||||
} catch (Exception e) {
|
|
||||||
String objectResponse = WebUtil.objectResponse(ResponseCode.TOKEN_IS_ILLEGAL, "Token is illegal", null);
|
|
||||||
WebUtil.renderString(response, objectResponse);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String redisKey = "login:" + token;
|
String redisKey = "login:" + token;
|
||||||
LoginUser loginUser = new ObjectMapper().convertValue(redisCache.getCacheObject(redisKey), LoginUser.class);
|
LoginUser loginUser = new ObjectMapper().convertValue(redisCache.getCacheObject(redisKey), LoginUser.class);
|
||||||
if (Objects.isNull(loginUser)) {
|
if (Objects.isNull(loginUser)) {
|
||||||
String objectResponse = WebUtil.objectResponse(ResponseCode.TOKEN_HAS_EXPIRED, "Token has expired", null);
|
throw new TokenHasExpiredException();
|
||||||
WebUtil.renderString(response, objectResponse);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
|
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
package com.cfive.pinnacle.handler;
|
package com.cfive.pinnacle.handler;
|
||||||
|
|
||||||
import com.cfive.pinnacle.entity.common.ResponseCode;
|
import jakarta.servlet.ServletException;
|
||||||
import com.cfive.pinnacle.utils.WebUtil;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.springframework.security.authentication.BadCredentialsException;
|
|
||||||
import org.springframework.security.authentication.InsufficientAuthenticationException;
|
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -15,15 +12,8 @@ import java.io.IOException;
|
|||||||
@Component
|
@Component
|
||||||
public class CustomAuthenticationEntryPointHandler implements AuthenticationEntryPoint {
|
public class CustomAuthenticationEntryPointHandler implements AuthenticationEntryPoint {
|
||||||
@Override
|
@Override
|
||||||
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
|
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
|
||||||
String objectResponse;
|
request.setAttribute("filter.error", authException);
|
||||||
if (authException instanceof BadCredentialsException) {
|
request.getRequestDispatcher("/error/thrown").forward(request, response);
|
||||||
objectResponse = WebUtil.objectResponse(ResponseCode.LOGIN_USERNAME_PASSWORD_ERROR, authException.getMessage(), null);
|
|
||||||
} else if (authException instanceof InsufficientAuthenticationException) {
|
|
||||||
objectResponse = WebUtil.objectResponse(ResponseCode.UNAUTHORIZED, authException.getMessage(), null);
|
|
||||||
} else {
|
|
||||||
objectResponse = WebUtil.objectResponse(ResponseCode.UNAUTHORIZED, authException.getClass().toString() + ": " + authException.getMessage(), null);
|
|
||||||
}
|
|
||||||
WebUtil.renderString(response, objectResponse);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
package com.cfive.pinnacle.handler;
|
package com.cfive.pinnacle.handler;
|
||||||
|
|
||||||
|
import com.auth0.jwt.exceptions.JWTDecodeException;
|
||||||
|
import com.auth0.jwt.exceptions.TokenExpiredException;
|
||||||
import com.cfive.pinnacle.entity.common.ResponseCode;
|
import com.cfive.pinnacle.entity.common.ResponseCode;
|
||||||
import com.cfive.pinnacle.entity.common.ResponseResult;
|
import com.cfive.pinnacle.entity.common.ResponseResult;
|
||||||
import com.cfive.pinnacle.exception.DataValidationFailedException;
|
import com.cfive.pinnacle.exception.DataValidationFailedException;
|
||||||
|
import com.cfive.pinnacle.exception.TokenHasExpiredException;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.dao.DataIntegrityViolationException;
|
import org.springframework.dao.DataIntegrityViolationException;
|
||||||
import org.springframework.dao.DuplicateKeyException;
|
import org.springframework.dao.DuplicateKeyException;
|
||||||
import org.springframework.security.access.AccessDeniedException;
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
import org.springframework.security.authentication.BadCredentialsException;
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
import org.springframework.security.authentication.DisabledException;
|
import org.springframework.security.authentication.DisabledException;
|
||||||
|
import org.springframework.security.authentication.InsufficientAuthenticationException;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
|
||||||
@@ -18,11 +22,20 @@ public class CustomExceptionHandler {
|
|||||||
|
|
||||||
@ExceptionHandler(value = Exception.class)
|
@ExceptionHandler(value = Exception.class)
|
||||||
public ResponseResult<?> exceptionHandler(Exception e) {
|
public ResponseResult<?> exceptionHandler(Exception e) {
|
||||||
|
if (e instanceof InsufficientAuthenticationException) {
|
||||||
|
return ResponseResult.build(ResponseCode.UNAUTHORIZED, e.getMessage(), null);
|
||||||
|
}
|
||||||
|
if (e instanceof JWTDecodeException) {
|
||||||
|
return ResponseResult.build(ResponseCode.TOKEN_IS_ILLEGAL, "Token is illegal", null);
|
||||||
|
}
|
||||||
|
if (e instanceof TokenHasExpiredException || e instanceof TokenExpiredException) {
|
||||||
|
return ResponseResult.build(ResponseCode.TOKEN_HAS_EXPIRED, "Token has expired", null);
|
||||||
|
}
|
||||||
if (e instanceof DuplicateKeyException) {
|
if (e instanceof DuplicateKeyException) {
|
||||||
return ResponseResult.build(ResponseCode.DATABASE_SAVE_ERROR, "无法添加重复数据", null);
|
return ResponseResult.build(ResponseCode.DATABASE_SAVE_ERROR, "无法添加重复数据", null);
|
||||||
}
|
}
|
||||||
if (e instanceof BadCredentialsException) {
|
if (e instanceof BadCredentialsException) {
|
||||||
return ResponseResult.build(ResponseCode.LOGOUT_FAILED, e.getMessage(), null);
|
return ResponseResult.build(ResponseCode.LOGIN_USERNAME_PASSWORD_ERROR, e.getMessage(), null);
|
||||||
}
|
}
|
||||||
if (e instanceof AccessDeniedException) {
|
if (e instanceof AccessDeniedException) {
|
||||||
return ResponseResult.build(ResponseCode.ACCESS_DENIED, e.getMessage(), null);
|
return ResponseResult.build(ResponseCode.ACCESS_DENIED, e.getMessage(), null);
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ public class JwtUtil {
|
|||||||
// String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJjYWM2ZDVhZi1mNjVlLTQ0MDAtYjcxMi0zYWEwOGIyOTIwYjQiLCJzdWIiOiJzZyIsImlzcyI6InNnIiwiaWF0IjoxNjM4MTA2NzEyLCJleHAiOjE2MzgxMTAzMTJ9.JVsSbkP94wuczb4QryQbAke3ysBDIL5ou8fWsbt_ebg";
|
// String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJjYWM2ZDVhZi1mNjVlLTQ0MDAtYjcxMi0zYWEwOGIyOTIwYjQiLCJzdWIiOiJzZyIsImlzcyI6InNnIiwiaWF0IjoxNjM4MTA2NzEyLCJleHAiOjE2MzgxMTAzMTJ9.JVsSbkP94wuczb4QryQbAke3ysBDIL5ou8fWsbt_ebg";
|
||||||
// Claims claims = parseJWT(token);
|
// Claims claims = parseJWT(token);
|
||||||
|
|
||||||
System.out.println(parseJWT("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJxd2UiLCJpc3MiOiJjZml2ZSIsImV4cCI6MTY4MzE5MzkyOSwiaWF0IjoxNjgzMTkwMzI5LCJqdGkiOiIzOWY5YTcxYTllY2E0Mjg1OGVjNGExODU2ZmQwYjk4OCJ9.4YOOILGWxlnmToWTdo4YoCbfXqvzdJF_Ds4zulDWX1o")
|
System.out.println(parseJWT("ayJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJxd2UiLCJpc3MiOiJjZml2ZSIsImV4cCI6MTY4MzE5MzkyOSwiaWF0IjoxNjgzMTkwMzI5LCJqdGkiOiIzOWY5YTcxYTllY2E0Mjg1OGVjNGExODU2ZmQwYjk4OCJ9.4YOOILGWxlnmToWTdo4YoCbfXqvzdJF_Ds4zulDWX1o")
|
||||||
.getClaims());
|
.getClaims());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,32 +1,10 @@
|
|||||||
package com.cfive.pinnacle.utils;
|
package com.cfive.pinnacle.utils;
|
||||||
|
|
||||||
import com.cfive.pinnacle.entity.common.ResponseResult;
|
|
||||||
import com.cfive.pinnacle.entity.permission.LoginUser;
|
import com.cfive.pinnacle.entity.permission.LoginUser;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class WebUtil {
|
public class WebUtil {
|
||||||
public static String convert2json(Object object) throws JsonProcessingException {
|
|
||||||
return new ObjectMapper().writeValueAsString(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String objectResponse(int resultCode, String msg, Object object) throws JsonProcessingException {
|
|
||||||
ResponseResult<Object> result = ResponseResult.build(resultCode, msg, object);
|
|
||||||
return convert2json(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void renderString(HttpServletResponse response, String string) throws IOException {
|
|
||||||
response.setStatus(200);
|
|
||||||
response.setContentType("application/json");
|
|
||||||
response.setCharacterEncoding("utf-8");
|
|
||||||
response.getWriter().print(string);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LoginUser getLoginUser() {
|
public static LoginUser getLoginUser() {
|
||||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
Object principal = authentication.getPrincipal();
|
Object principal = authentication.getPrincipal();
|
||||||
|
|||||||
Reference in New Issue
Block a user