【问题标题】:Spring Boot Oauth2 Refresh Token - IllegalStateExceptionSpring Boot Oauth2 刷新令牌 - IllegalStateException
【发布时间】:2015-06-02 20:32:00
【问题描述】:

因此,我可以使用标准 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));
    }

}
}

和网络安全配置:

@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. 为什么在用户详细信息服务明确存在并事先为密码授予工作时却找不到?

谢谢

【问题讨论】:

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


    【解决方案1】:

    我使用的是 spring boot + OAuth2,遇到了同样的异常
    IllegalStateException - UserDetailsService Required.

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

    1. WebSecurityConfig(extends 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(extends 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
      
      }
      

    【讨论】:

    • 如果您的配置将 inMemoryAuthentication() 与默认的 UserDetailsS​​ervice 结合使用,这是最佳答案。我已经尝试了 3 或 4 种方法,但是这绝对是最简单和最干净的方法。
    【解决方案2】:

    在这里找到答案: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());
        }
    
    }
    

    作为解决方案 cmets 的作者,“全局身份验证配置在 Spring Boot 中排序之后(因此此处的设置会覆盖 Boot 中的设置)。”尽管他还提到这在 spring boot 1.2.3 中无论如何都不会成为问题,但现在我需要让它工作并找到我的 UserDetailsS​​ervice。

    【讨论】:

      【解决方案3】:

      在您的 AuthorizationServerConfig 类中:

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

      【讨论】:

        猜你喜欢
        • 2012-07-21
        • 2017-12-02
        • 2017-01-01
        • 2017-04-14
        • 2015-08-31
        • 2016-03-07
        • 2020-08-16
        • 2017-04-20
        • 1970-01-01
        相关资源
        最近更新 更多