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

相關文章
相關標籤/搜索