美文网首页Spring Security我爱编程微服务架构
Spring Security Oauth2 自定义 OAuth

Spring Security Oauth2 自定义 OAuth

作者: 淡淡的伤你 | 来源:发表于2018-05-27 20:29 被阅读227次

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

    https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/spring-security-OAuth208.png

    前言

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

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

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

    
    {
    "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://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth209.gif

    token异常

    https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth210.gif

    禁止访问

    https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth211.gif

    token失效

    https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth212.gif

    代码下载

    推荐文章

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

    https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/wechat/xiaochengxu.png

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

    相关文章

      网友评论

        本文标题:Spring Security Oauth2 自定义 OAuth

        本文链接:https://www.haomeiwen.com/subject/ondijftx.html