这篇文章主要为大家展示了“SpringBoot Security如何自定义异常处理”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“SpringBoot Security如何自定义异常处理”这篇文章吧。
SpringBoot Security自定义异常
access_denied 方面异常
原异常
{ "error": "access_denied", "error_description": "不允许访问"}
现异常
{ "success": false, "error": "access_denied", "status": 403, "message": "不允许访问", "path": "/user/get1", "timestamp": 1592378892768}
实现
public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Override public void configure(ResourceServerSecurityConfigurer resources) { // access_denied 方面异常 OAuth3AccessDeniedHandler oAuth3AccessDeniedHandler = new OAuth3AccessDeniedHandler(); oAuth3AccessDeniedHandler.setExceptionTranslator(new CustomWebResponseExceptionTranslator()); resources.accessDeniedHandler(oAuth3AccessDeniedHandler); }}
Invalid access token 方面异常
原异常
{ "error": "invalid_token", "error_description": "Invalid access token: 4eb58ecf-e66de-4155-9477-64a1c9805cc8"}
现异常
{ "success": false, "error": "invalid_token", "status": 401, "message": "Invalid access token: 8cd45925dbf6-4502-bd13-8101bc6e1d4b", "path": "/user/get1", "timestamp": 1592378949452}
实现
public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Override public void configure(ResourceServerSecurityConfigurer resources) { // Invalid access token 方面异常 OAuth3AuthenticationEntryPoint authenticationEntryPoint = new OAuth3AuthenticationEntryPoint(); authenticationEntryPoint.setExceptionTranslator(new CustomWebResponseExceptionTranslator()); resources.authenticationEntryPoint(authenticationEntryPoint); }}
Bad credentials 方面异常(登陆出错)
原异常
{ "error": "invalid_grant", "error_description": "用户名或密码错误"}
现异常
{ "success": false, "error": "invalid_grant", "status": 400, "message": "用户名或密码错误", "path": "/oauth/token", "timestamp": 1592384576019}
实现
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) { endpoints.userDetailsService(detailsService) .tokenStore(memoryTokenStore()) .exceptionTranslator(new CustomWebResponseExceptionTranslator()) .authenticationManager(authenticationManager) //接收GET和POST .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST); }}
其他类
@Getter@JsonSerialize(using = CustomOauthExceptionSerializer.class)public class CustomOauthException extends OAuth3Exception { private String oAuth3ErrorCode; private int httpErrorCode; public CustomOauthException(String msg, String oAuth3ErrorCode, int httpErrorCode) { super(msg); this.oAuth3ErrorCode = oAuth3ErrorCode; this.httpErrorCode = httpErrorCode; }}
public class CustomOauthExceptionSerializer extends StdSerializer<CustomOauthException> { private static final long serialVersionUID = 2652127645704345563L; public CustomOauthExceptionSerializer() { super(CustomOauthException.class); } @Override public void serialize(CustomOauthException value, JsonGenerator gen, SerializerProvider provider) throws IOException { gen.writeStartObject(); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); gen.writeObjectField("success",false); gen.writeObjectField("error",value.getOAuth3ErrorCode()); gen.writeObjectField("status", value.getHttpErrorCode()); gen.writeObjectField("message", value.getMessage()); gen.writeObjectField("path", request.getServletPath()); gen.writeObjectField("timestamp", (new Date()).getTime()); if (value.getAdditionalInformation()!=null) { for (Map.Entry<String, String> entry : value.getAdditionalInformation().entrySet()) { String key = entry.getKey(); String add = entry.getValue(); gen.writeObjectField(key, add); } } gen.writeEndObject(); }}
public class CustomWebResponseExceptionTranslator extends DefaultWebResponseExceptionTranslator { @Override public ResponseEntity<OAuth3Exception> translate(Exception e) throws Exception { ResponseEntity<OAuth3Exception> translate = super.translate(e); OAuth3Exception body = translate.getBody(); CustomOauthException customOauthException = new CustomOauthException(body.getMessage(),body.getOAuth3ErrorCode(),body.getHttpErrorCode()); ResponseEntity<OAuth3Exception> response = new ResponseEntity<>(customOauthException, translate.getHeaders(), translate.getStatusCode()); return response; }}
补充
{ "error": "invalid_client", "error_description": "Bad client credentials"}
如果client_secret错误依然还是报错,如上内容,针对这个异常需要在如下方法中的addTokenEndpointAuthenticationFilter添加过滤器处理
@Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) { oauthServer // 开启/oauth/token_key验证端口无权限访问 .tokenKeyAccess("permitAll()") // 开启/oauth/check_token验证端口认证权限访问 .checkTokenAccess("isAuthenticated()") .addTokenEndpointAuthenticationFilter(null) .allowFormAuthenticationForClients(); }
SpringSecurity自定义响应异常信息
此处的异常信息设置的话,其中还是有坑的,比如你想自定义token过期信息,无效token这些,如果按照SpringSecurity的设置是不会生效的,需要加到资源的配置中。
如果只是SpringSecurity的话,只需要实现AccessDeniedHandler和AuthenticationEntryPoint这2个接口就可以了。他们都是在ExceptionTranslationFilter中生效的。
AuthenticationEntryPoint
用来解决匿名用户访问无权限资源时的异常ruAccessDeineHandler
用来解决认证过的用户访问无权限资源时的异常
如果你想自定义token过期的话,需要实现AuthenticationEntryPoint这个接口,因为token过期了,访问的话也算是匿名访问。
但是SpringSecurity的过滤器链中其实是有顺序的,校验token的OAuth3AuthenticationProcessingFilter在它前面,导致一直没有办法生效,所有需要添加到资源的配置上,demo如下:
@Componentpublic class SimpleAuthenticationEntryPoint implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws ServletException { Throwable cause = authException.getCause(); try { if (cause instanceof InvalidTokenException) { Map map = new HashMap(); map.put("error", "无效token"); map.put("message", authException.getMessage()); map.put("path", request.getServletPath()); map.put("timestamp", String.valueOf(new Date().getTime())); response.setContentType("application/json"); response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); try { ObjectMapper mapper = new ObjectMapper(); mapper.writeValue(response.getOutputStream(), map); } catch (Exception e) { throw new ServletException(); } } } catch (Exception e) { e.printStackTrace(); } }}
则可以生效,返回信息具体如下:
如果想设置没有权限的自定义异常信息的话:
@Componentpublic class SimpleAccessDeniedHandler implements AccessDeniedHandler { @Override public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { Map map = new HashMap(); map.put("message", "无权操作"); map.put("path", request.getServletPath()); map.put("timestamp", String.valueOf(new Date().getTime())); response.setContentType("application/json"); response.setStatus(HttpServletResponse.SC_FORBIDDEN); try { ObjectMapper mapper = new ObjectMapper(); mapper.writeValue(response.getOutputStream(), map); } catch (Exception e) { throw new ServletException(); } }}
把它设置到springsecurity中,添加进去就可以了,如果不是想要捕获token过期的话,就直接添加进去也可以
以上是“SpringBoot Security如何自定义异常处理”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网行业资讯频道!