博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
@ExceptionHandler不管用 spring security oauth2 自定义异常拦截InternalAuthenticationServiceException
阅读量:2059 次
发布时间:2019-04-29

本文共 8392 字,大约阅读时间需要 27 分钟。

由于spring security的认证原理是通过注册到tomcat容器的filter链上,使得认证异常不能通过DispatcherServlet来捕获异常,所以@ExceptionHandler处理不到

//AuthenticationEntryPoint{    "error": "unauthorized",    "error_description": "Full authentication is required to access this resource"}或者//AccessDeniedHandler{    "error": "invalid_token",    "error_description": "Invalid access token: 82b47091-c752-4832-b5dd-96a4da4df999"}{    "error": "access_denied",    "error_description": "not allowed access"}

spring security oauth2主要分为两块:认证服务器与资源服务器

认证服务器,就是**/oauth/token** 登录获取认证token
资源服务器,就是管理那些url资源需要被认证和权限检查,资源服务器ResourceServerConfiguration会配置需要检查权限的url

有时候配置好认证服务器,可以获取token,但是访问资源url还是报错access_denied,试试下面配置

//下面的order值看OAuth2 版本security.oauth2.resource.filter-order = 3或者@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) on WebSecurityConfigurerAdapter class

所以spring security oauth2的异常会出现在两处

  • 登录认证 /oauth/token 获取token时
  • 访问其他资源类url时

所以自定义异常需要配置两处

@Configuration@EnableAuthorizationServerpublic class OAuthSecurityConfig extends AuthorizationServerConfigurerAdapter {    @Override    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {        //自定义 /oauth/token 异常处理        endpoints.exceptionTranslator(new MyWebResponseExceptionTranslator());    }}@Configuration@EnableResourceServerpublic  class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {        @Override        public void configure(ResourceServerSecurityConfigurer resources) {            //自定义资源访问认证异常,没有token,或token错误,使用MyAuthenticationEntryPoint            resources.authenticationEntryPoint(new MyAuthenticationEntryPoint());            resources.accessDeniedHandler(new MyAccessDeniedHandler());        }}
//实现根据用户名获取用户信息@Componentpublic class UserDetailServiceImpl implements UserDetailsService {    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {        if(user==null)            // throw OAuth2Exception.create(OAuth2Exception.INVALID_REQUEST, "无此用户名");            throw new UsernameNotFoundException("无此用户名");    }}// 默认出于安全考虑,会把UsernameNotFoundException转为BadCredentialsException,就是 “坏的凭据”,注入下面配置的bean@Bean    public AuthenticationProvider daoAuthenticationProvider(UserDetailsService userDetailsService) {        DaoAuthenticationProvider impl = new DaoAuthenticationProvider();        impl.setUserDetailsService(userDetailsService);        impl.setHideUserNotFoundExceptions(false) ;        return impl ;    }

对于登录认证异常处理配置,然后是处理类,通过WebResponseExceptionTranslator转为自定义的OAuth2Exception,然后使用jackson定制化类的json序列化,达到自定义异常信息的目的。

OAuth2Exception 本身是继承RuntimeException,而且被OAuth2ExceptionJackson1Serializer序列化,所以我们要做的就是自定义一个OAuth2Exception 子类 和这个子类的序列化

import org.springframework.http.HttpStatus;import org.springframework.http.ResponseEntity;import org.springframework.security.core.AuthenticationException;import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;/** * @author zhanghui * @date 2019/6/21 */public class MyWebResponseExceptionTranslator implements WebResponseExceptionTranslator {    @Override    public ResponseEntity
translate(Exception exception) throws Exception { if (exception instanceof OAuth2Exception) { OAuth2Exception oAuth2Exception = (OAuth2Exception) exception; return ResponseEntity .status(oAuth2Exception.getHttpErrorCode()) .body(new CustomOauthException(oAuth2Exception.getMessage())); }else if(exception instanceof AuthenticationException){ AuthenticationException authenticationException = (AuthenticationException) exception; return ResponseEntity .status(HttpStatus.UNAUTHORIZED) .body(new CustomOauthException(authenticationException.getMessage())); } return ResponseEntity .status(HttpStatus.OK) .body(new CustomOauthException(exception.getMessage())); }}
import com.fasterxml.jackson.databind.annotation.JsonSerialize;import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;/** * @author zhanghui * @date 2019/6/21 */@JsonSerialize(using = CustomOauthExceptionSerializer.class)public class CustomOauthException extends OAuth2Exception {    public CustomOauthException(String msg) {        super(msg);    }}
import com.fasterxml.jackson.core.JsonGenerator;import com.fasterxml.jackson.databind.SerializerProvider;import com.fasterxml.jackson.databind.ser.std.StdSerializer;import java.io.IOException;import java.util.Arrays;import java.util.Map;/** * @author zhanghui * @date 2019/6/21 */public class CustomOauthExceptionSerializer extends StdSerializer
{ public CustomOauthExceptionSerializer() { super(CustomOauthException.class); } @Override public void serialize(CustomOauthException value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { //可以不用下面的代码,只用 jsonGenerator.writeRawValue(myJsonString) 输出自定义字符串 jsonGenerator.writeStartObject(); jsonGenerator.writeNumberField("code4444", value.getHttpErrorCode()); jsonGenerator.writeBooleanField("status", false); jsonGenerator.writeObjectField("data", null); jsonGenerator.writeObjectField("errors", Arrays.asList(value.getOAuth2ErrorCode(),value.getMessage())); if (value.getAdditionalInformation()!=null) { for (Map.Entry
entry : value.getAdditionalInformation().entrySet()) { String key = entry.getKey(); String add = entry.getValue(); jsonGenerator.writeStringField(key, add); } } jsonGenerator.writeEndObject(); }}

对于资源访问的异常自定义

import com.fasterxml.jackson.databind.ObjectMapper;import org.springframework.security.core.AuthenticationException;import org.springframework.security.web.AuthenticationEntryPoint;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.util.Date;import java.util.HashMap;import java.util.Map;/** * @author zhanghui * @date 2019/6/21 */public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {    @Override    public void commence(HttpServletRequest request, HttpServletResponse response,                         AuthenticationException authException)            throws ServletException {        Map map = new HashMap();        map.put("errorentry", "401");        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();        }    }}
import com.fasterxml.jackson.databind.ObjectMapper;import org.springframework.security.access.AccessDeniedException;import org.springframework.security.web.access.AccessDeniedHandler;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.Date;import java.util.HashMap;import java.util.Map;/** * @author zhanghui * @date 2019/6/21 */public class MyAccessDeniedHandler implements AccessDeniedHandler{    @Override    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {        response.setContentType("application/json;charset=UTF-8");        Map map = new HashMap();        map.put("errorauth", "400");        map.put("message", accessDeniedException.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();        }    }}

转载地址:http://vyalf.baihongyu.com/

你可能感兴趣的文章
(PAT 1061) Dating (字符串处理)
查看>>
(PAT 1118) Birds in Forest (并查集)
查看>>
数据结构 拓扑排序
查看>>
(PAT 1040) Longest Symmetric String (DP-最长回文子串)
查看>>
(PAT 1145) Hashing - Average Search Time (哈希表冲突处理)
查看>>
(1129) Recommendation System 排序
查看>>
PAT1090 Highest Price in Supply Chain 树DFS
查看>>
(PAT 1096) Consecutive Factors (质因子分解)
查看>>
(PAT 1019) General Palindromic Number (进制转换)
查看>>
(PAT 1073) Scientific Notation (字符串模拟题)
查看>>
(PAT 1080) Graduate Admission (排序)
查看>>
Play on Words UVA - 10129 (欧拉路径)
查看>>
mininet+floodlight搭建sdn环境并创建简答topo
查看>>
【linux】nohup和&的作用
查看>>
【UML】《Theach yourself uml in 24hours》——hour4
查看>>
Set、WeakSet、Map以及WeakMap结构基本知识点
查看>>
【NLP学习笔记】(一)Gensim基本使用方法
查看>>
【NLP学习笔记】(二)gensim使用之Topics and Transformations
查看>>
【深度学习】LSTM的架构及公式
查看>>
【深度学习】GRU的结构图及公式
查看>>