Spring Security Oauth2 自定义 OAuth2 Exception

付出就要获得回报,这种想法是错的。java

https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/spring-security-OAuth208.png
https://user-gold-cdn.xitu.io/2018/5/27/163a194a8f506f26?w=2248&h=1500&f=jpeg&s=197133

前言

在使用Spring Security Oauth2登陆和鉴权失败时,默认返回的异常信息以下git

{
  "error": "unauthorized",
  "error_description": "Full authentication is required to access this resource"
}
复制代码

。它与咱们自定义返回信息不一致,而且描述信息较少。那么如何自定义Spring Security Oauth2异常信息呢,下面咱们简单实现如下。格式以下:github

{
"error": "400",
"message": "坏的凭证",
"path": "/oauth/token",
"timestamp": "1527432468717"
}
复制代码

自定义登陆失败异常信息

新增CustomOauthException

  • 添加自定义异常类,指定json序列化方式
@JsonSerialize(using = CustomOauthExceptionSerializer.class)
public class CustomOauthException extends OAuth2Exception {
    public CustomOauthException(String msg) {
        super(msg);
    }
}
复制代码

新增CustomOauthExceptionSerializer

  • 添加CustomOauthException的序列化实现
public class CustomOauthExceptionSerializer extends StdSerializer<CustomOauthException> {
    public CustomOauthExceptionSerializer() {
        super(CustomOauthException.class);
    }

    @Override
    public void serialize(CustomOauthException value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

        gen.writeStartObject();
        gen.writeStringField("error", String.valueOf(value.getHttpErrorCode()));
        gen.writeStringField("message", value.getMessage());
// gen.writeStringField("message", "用户名或密码错误");
        gen.writeStringField("path", request.getServletPath());
        gen.writeStringField("timestamp", String.valueOf(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.writeStringField(key, add);
            }
        }
        gen.writeEndObject();
    }
}

复制代码

添加CustomWebResponseExceptionTranslator

  • 添加CustomWebResponseExceptionTranslator,登陆发生异常时指定exceptionTranslator
public class CustomOauthExceptionSerializer extends StdSerializer<CustomOauthException> {
    public CustomOauthExceptionSerializer() {
        super(CustomOauthException.class);
    }

    @Override
    public void serialize(CustomOauthException value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

        gen.writeStartObject();
        gen.writeStringField("error", String.valueOf(value.getHttpErrorCode()));
        gen.writeStringField("message", value.getMessage());
// gen.writeStringField("message", "用户名或密码错误");
        gen.writeStringField("path", request.getServletPath());
        gen.writeStringField("timestamp", String.valueOf(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.writeStringField(key, add);
            }
        }
        gen.writeEndObject();
    }
}

复制代码

修改MerryyouAuthorizationServerConfig

  • 指定自定义customWebResponseExceptionTranslator
@Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore)
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService);
        //扩展token返回结果
        if (jwtAccessTokenConverter != null && jwtTokenEnhancer != null) {
            TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
            List<TokenEnhancer> enhancerList = new ArrayList();
            enhancerList.add(jwtTokenEnhancer);
            enhancerList.add(jwtAccessTokenConverter);
            tokenEnhancerChain.setTokenEnhancers(enhancerList);
            //jwt
            endpoints.tokenEnhancer(tokenEnhancerChain)
                    .accessTokenConverter(jwtAccessTokenConverter);
        }
        endpoints.exceptionTranslator(customWebResponseExceptionTranslator);
    }

复制代码

自定义Token异常信息

添加AuthExceptionEntryPoint

  • 自定义AuthExceptionEntryPoint用于tokan校验失败返回信息
public class AuthExceptionEntryPoint implements AuthenticationEntryPoint {


    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws ServletException {

        Map map = new HashMap();
        map.put("error", "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();
        }
    }
}
复制代码

添加CustomAccessDeniedHandler

  • 受权失败(forbidden)时返回信息
@Slf4j
@Component("customAccessDeniedHandler")
public class CustomAccessDeniedHandler implements AccessDeniedHandler {

    @Autowired
    private ObjectMapper objectMapper;

    @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("error", "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);
            response.getWriter().write(objectMapper.writeValueAsString(map));
    }
}
复制代码

修改MerryyouResourceServerConfig

@Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.authenticationEntryPoint(new AuthExceptionEntryPoint())
        .accessDeniedHandler(CustomAccessDeniedHandler);
    }
复制代码

效果以下

登陆异常

https://user-gold-cdn.xitu.io/2018/5/27/163a194a95131f78?w=1844&h=1015&f=gif&s=540014
https://user-gold-cdn.xitu.io/2018/5/27/163a194a95131f78?w=1844&h=1015&f=gif&s=540014

token异常

https://user-gold-cdn.xitu.io/2018/5/27/163a194a8944f75a?w=1844&h=1015&f=gif&s=332233
https://user-gold-cdn.xitu.io/2018/5/27/163a194a8944f75a?w=1844&h=1015&f=gif&s=332233

禁止访问

https://user-gold-cdn.xitu.io/2018/5/27/163a194a88807c3b?w=1844&h=1015&f=gif&s=402198
https://user-gold-cdn.xitu.io/2018/5/27/163a194a88807c3b?w=1844&h=1015&f=gif&s=402198

token失效

https://user-gold-cdn.xitu.io/2018/5/27/163a194a8f7dd59d?w=1844&h=1015&f=gif&s=458018
https://user-gold-cdn.xitu.io/2018/5/27/163a194a8f7dd59d?w=1844&h=1015&f=gif&s=458018

代码下载

推荐文章

  1. Java建立区块链系列
  2. Spring Security源码分析系列
  3. Spring Data Jpa 系列
  4. 【译】数据结构中关于树的一切(java版)
  5. SpringBoot+Docker+Git+Jenkins实现简易的持续集成和持续部署

https://user-gold-cdn.xitu.io/2018/5/27/163a194a87e01e0c?w=301&h=330&f=png&s=78572
https://user-gold-cdn.xitu.io/2018/5/27/163a194a87e01e0c?w=301&h=330&f=png&s=78572

🙂🙂🙂关注微信小程序java架构师历程 上下班的路上无聊吗?还在看小说、新闻吗?不知道怎样提升本身的技术吗?来吧这里有你须要的java架构文章,1.5w+的java工程师都在看,你还在等什么?spring

相关文章
相关标签/搜索