Spring:OAuth2的ExceptionTranslator无法正常工作

时间:2017-10-01 21:32:38

标签: spring jhipster spring-security-oauth2

在具有OAuth2的Spring中,如果访问令牌无效,则会出现InvalidTokenException并输出:

{"error":"invalid_token","error_description":"Invalid access token: asdfasdf"}

以json格式。

我正在尝试自定义输出,例如

{"code": 123, "error":"invalid_token","error_description":"Invalid access token: asdfasdf"}

为了做到这一点,我在Github https://github.com/spring-projects/spring-security-oauth/issues/375上遵循了这个例子,我的代码如下所示。问题是我的webResponseExceptionTranslator()永远不会被调用。有什么问题?

package com.my.config;

import....

@Configuration
public class OAuth2ServerConfiguration {

    private final DataSource dataSource;

    public OAuth2ServerConfiguration(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Bean
    public JdbcTokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }

    @Configuration
    @EnableResourceServer
    protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

        private final TokenStore tokenStore;

        private final Http401UnauthorizedEntryPoint http401UnauthorizedEntryPoint;

        private final AjaxLogoutSuccessHandler ajaxLogoutSuccessHandler;

        private final CorsFilter corsFilter;

        public ResourceServerConfiguration(TokenStore tokenStore, Http401UnauthorizedEntryPoint http401UnauthorizedEntryPoint,
                                           AjaxLogoutSuccessHandler ajaxLogoutSuccessHandler, CorsFilter corsFilter) {

            this.tokenStore = tokenStore;
            this.http401UnauthorizedEntryPoint = http401UnauthorizedEntryPoint;
            this.ajaxLogoutSuccessHandler = ajaxLogoutSuccessHandler;
            this.corsFilter = corsFilter;
        }

        @Override
        public void configure(HttpSecurity http) throws Exception {
            http
                .exceptionHandling()
                .authenticationEntryPoint(http401UnauthorizedEntryPoint)
                .and()
                .logout()
                .logoutUrl("/api/logout")
                .logoutSuccessHandler(ajaxLogoutSuccessHandler)
                .and()
                .csrf()
                .disable()
                .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
                .headers()
                .frameOptions().disable()
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                .antMatchers("/api/authenticate").permitAll()
                .antMatchers("/api/register").permitAll()
                .antMatchers("/api/profile-info").permitAll()
                .antMatchers("/api/**").authenticated()
                .antMatchers(G.IFTTT_PATH).permitAll()
                .antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN)
                .antMatchers("/v2/api-docs/**").permitAll()
                .antMatchers("/swagger-resources/configuration/ui").permitAll()
                .antMatchers("/swagger-ui/index.html").hasAuthority(AuthoritiesConstants.ADMIN);
        }

        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources.resourceId("res_q").tokenStore(tokenStore)
                .accessDeniedHandler(new OAuth2AccessDeniedHandler());
        }
    }

    @Configuration
    @EnableAuthorizationServer
    protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

        private final AuthenticationManager authenticationManager;

        private final TokenStore tokenStore;

        private final DataSource dataSource;

        public AuthorizationServerConfiguration(@Qualifier("authenticationManagerBean") AuthenticationManager authenticationManager,
                                                TokenStore tokenStore, DataSource dataSource) {

            this.authenticationManager = authenticationManager;
            this.tokenStore = tokenStore;
            this.dataSource = dataSource;
        }

        @Bean
        protected AuthorizationCodeServices authorizationCodeServices() {
            return new JdbcAuthorizationCodeServices(dataSource);
        }


        @Bean
        public WebResponseExceptionTranslator webResponseExceptionTranslator() {
            return new DefaultWebResponseExceptionTranslator() {

                @Override
                public ResponseEntity<OAuth2Exception> translate(Exception e) throws Exception {
                    // ==================== never gets called ===============
                    ResponseEntity<OAuth2Exception> responseEntity = super.translate(e);
                    OAuth2Exception body = responseEntity.getBody();
                    HttpHeaders headers = new HttpHeaders();
                    headers.setAll(responseEntity.getHeaders().toSingleValueMap());
                    // do something with header or response
                    System.out.println("========================== in webResponseExceptionTranslator  ===============================");
                    return new ResponseEntity<>(body, headers, responseEntity.getStatusCode());
                }
            };
        }

        @Bean
        public ApprovalStore approvalStore() {
            return new JdbcApprovalStore(dataSource);
        }

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints)
            throws Exception {
            endpoints
                //========================== here ====================
                .exceptionTranslator(webResponseExceptionTranslator())
                //====================================================
                .authorizationCodeServices(authorizationCodeServices())
                .approvalStore(approvalStore())
                .tokenStore(tokenStore)
                .authenticationManager(authenticationManager);
        }


        @Override
        public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
            oauthServer.allowFormAuthenticationForClients();
        }

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.jdbc(dataSource);
        }
    }
}

1 个答案:

答案 0 :(得分:0)

我用于自定义默认oauth错误消息的有效解决方案是:

@Configurationpublic class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

@Override
public void configure(ResourceServerSecurityConfigurer resources) {
    OAuth2AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
    authenticationEntryPoint.setExceptionTranslator(new CustomWebResponseExceptionTranslator());
    resources.authenticationEntryPoint(authenticationEntryPoint);
}

private class CustomWebResponseExceptionTranslator extends DefaultWebResponseExceptionTranslator  {
    @Override
    public ResponseEntity<OAuth2Exception> translate(Exception e) throws Exception {
        ResponseEntity<OAuth2Exception> responseEntity = super.translate(e);
        OAuth2Exception body = responseEntity.getBody();
        HttpHeaders headers = new HttpHeaders();
        headers.setAll(responseEntity.getHeaders().toSingleValueMap());
        // do something with header or response
        return new ResponseEntity<>(body, headers, responseEntity.getStatusCode());
    }
}

}