Spring Boot Oauth2刷新令牌 - IllegalStateException

时间:2015-03-29 22:44:33

标签: spring spring-security oauth-2.0 spring-boot

因此,我可以使用标准CURL获得访问令牌,但是一旦我尝试获取访问令牌,应用程序就会抛出“IllegalStateException - UserDetailsS​​ervice Required'”。据我所知,一旦刷新令牌,我们就不需要再次验证用户详细信息了吗?但无论如何它应该在那里,因为它必须首次验证访问令牌。

见下面我的Oauth2配置:

@Configuration
public class OAuth2Config {

@Configuration
@EnableResourceServer
protected static class ResourceServiceConfig extends ResourceServerConfigurerAdapter {

    @Autowired
    private TokenStore tokenStore;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .antMatchers("/oauth/token/").permitAll()
            .antMatchers(HttpMethod.GET, "/api/**").access("#oauth2.hasScope('read')")
            .antMatchers(HttpMethod.OPTIONS, "/api/**").access("#oauth2.hasScope('read')")
            .antMatchers(HttpMethod.POST, "/api/**").access("#oauth2.hasScope('write')")
            .antMatchers(HttpMethod.PUT, "/api/v1/**").access("#oauth2.hasScope('write')")
            .antMatchers(HttpMethod.PATCH, "/api/**").access("#oauth2.hasScope('write')")
            .antMatchers(HttpMethod.DELETE, "/api/**").access("#oauth2.hasScope('write')");
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources
            .resourceId(<RESOURCE ID>)
            .tokenStore(tokenStore);
    }
}

@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Value("${oauth.clientid}")
    private String CLIENT_ID;

    @Value("${oauth.clientsecret}")
    private String CLIENT_SECRET;

    @Value("${oauth.tokenvalidity}")
    private String VALIDITY_SECONDS;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

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

    @Autowired
    @Qualifier("authenticationManagerBean")
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
            .tokenStore(tokenStore())
            .authenticationManager(authenticationManager);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients
            .withClient(CLIENT_ID)
            .scopes("read", "write")
            .authorities(Authorities.USER)
            .authorizedGrantTypes("password", "refresh_token")
            .secret(CLIENT_SECRET)
            .accessTokenValiditySeconds(Integer.parseInt(VALIDITY_SECONDS));
    }

}
}

和Web安全配置:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private CustomUserDetailsService userDetailsService;

@Bean
public BCryptPasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}


@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth
        .userDetailsService(userDetailsService)
        .passwordEncoder(passwordEncoder());
}

@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
}

@Override
public void configure(HttpSecurity http) throws Exception {
    http
        .csrf().disable()
        .authorizeRequests().anyRequest().permitAll();
}

}

所以是的,这个似乎没有意义,因为1.当我们尝试刷新令牌授权时,为什么它甚至会用于用户详细信息服务? 2.为什么当它显然存在并且事先为密码授权工作时,它无法找到用户详细信息服务?

由于

3 个答案:

答案 0 :(得分:0)

在这里找到答案:https://github.com/spring-projects/spring-security-oauth/blob/master/tests/annotation/jdbc/src/main/java/demo/Application.java#L136

我将此作为另一个内部类添加到我的Oauth配置类中,并从Web Security Config类中删除了任何身份验证管理器/密码编码器配置,实际上目前唯一剩下的就是配置上的@Override( HttpSecurity http)功能。

@Configuration
@Order(Ordered.LOWEST_PRECEDENCE - 20)
protected static class AuthenticationManagerConfiguration extends GlobalAuthenticationConfigurerAdapter {

    @Autowired
    private DataSource dataSource;

    @Autowired
    private CustomUserDetailsService userDetailsService;

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    public void init(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .userDetailsService(userDetailsService)
            .passwordEncoder(passwordEncoder());
    }

}

作为解决方案的作者注释&#34;全局身份验证配置在之后在Spring Boot中命令(因此这里的设置会覆盖Boot中的设置)。&#34;虽然他也提到这在春季启动1.2.3中不会成为一个问题,但是现在这就是我需要让它工作并找到我的UserDetailsS​​ervice。

答案 1 :(得分:0)

在AuthorizationServerConfig类中:

@Autowired
private CustomUserDetailsService userDetailsService;

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    endpoints
        .authenticationManager(authenticationManager)
        .tokenStore(tokenStore())
        .userDetailsService(userDetailsService);
}

答案 2 :(得分:0)

我正在使用Spring Boot + OAuth2,并且遇到相同的异常
IllegalStateException - UserDetailsService Required

我正在用内存身份验证管理器进行测试。我解决如下

  1. WebSecurityConfig(扩展了WebSecurityConfigurerAdapter)-清除默认的bean UserDetailsS​​ervice

    @Configuration
    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        @Bean("userDetailsService")
        public UserDetailsService userDetailsServiceBean() throws Exception {
            return super.userDetailsServiceBean(); //default
        }
    
        // other logics
    
    }
    
  2. OAuth2ServerConfig(扩展了AuthorizationServerConfigurerAdapter)-将UserDetailsS​​ervice bean注入oAuth2配置

    @Configuration
    @EnableAuthorizationServer
    public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
    
        @Autowired
        @Qualifier("userDetailsService")
        private UserDetailsService userDetailsService;
    
        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
            .authenticationManager(authenticationManager)
            .tokenStore(tokenStore)
            .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
            .userDetailsService(userDetailsService); //inject here
        }
    
        // other logics
    
    }