与oauth2 + jwt一起配置多个身份验证提供程序

时间:2019-06-08 18:40:58

标签: spring-boot spring-security spring-security-oauth2

我正在尝试使用JWT授权服务器配置Spring Boot 2,OAuth2,这需要执行以下操作:

  1. 获取用户名/密码,基于数据库数据和salesforce数据构建CustomUserDetails对象,并在身份验证通过的情况下返回JWT令牌(可行)
  2. 获取刷新令牌并返回新的JWT刷新和访问令牌(此方法有效)
  3. (新)获取一个刷新令牌,在返回新的JWT访问+刷新令牌之前,请在db中检查存储的令牌ID(这是麻烦点),这样做的目的是确保仅使用一个设备登录一次显示用户的凭据。

为了执行#3,我试图通过给它一个自定义PreAuthenticatedAuthenticationProvider来自定义UserDetailsService,并且AuthenticationManagerBuilder bean必须同时传递自定义的{{1 }}和PreAuthenticatedAuthenticationProvider

假设我正朝着正确的方向前进,这是我的配置代码:

DaoAuthenticationProvider

@Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired UserDetailsService userDetailsService; @Autowired PasswordEncoder passwordEncoder; //implements AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> @Autowired CustomPreauthenticatedUserDetailsService customPreauthenticatedUserDetailsService; @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/actuator/**").permitAll() .antMatchers("/swagger-ui**","/webjars/**","/swagger-resources/**", "/v2/**").permitAll() .antMatchers("/oauth/token/revokeById/**").permitAll() .antMatchers("/oauth/token/**").permitAll() .anyRequest().authenticated() .and().csrf().disable(); } @Autowired public void configureGlobal(AuthenticationManagerBuilder authenticationManager) throws Exception { authenticationManager.authenticationProvider(preauthAuthProvider()); authenticationManager.authenticationProvider(dbAuthProvider()); } @Bean @Qualifier(value = "authenticationManagerBean") @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Bean(value="preAuthProvider") public PreAuthenticatedAuthenticationProvider preauthAuthProvider() { PreAuthenticatedAuthenticationProvider preauthAuthProvider = new PreAuthenticatedAuthenticationProvider(); LOGGER.info("Setting customPreauthenticatedUserDetailsService"); preauthAuthProvider.setPreAuthenticatedUserDetailsService(customPreauthenticatedUserDetailsService); return preauthAuthProvider; } @Bean(value="dbAuthProvider") public DaoAuthenticationProvider dbAuthProvider() { DaoAuthenticationProvider dbAuthProvider = new DaoAuthenticationProvider(); dbAuthProvider.setUserDetailsService(userDetailsService); dbAuthProvider.setPasswordEncoder(passwordEncoder); return dbAuthProvider; } } 端:

AuthorizationServerConfig

启动该应用程序后,我发现出现问题的第一个迹象是:

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    private static final Integer ACCESS_TOKEN_VALIDITY_SECONDS = 300;
    private static final Integer REFRESH_TOKEN_VALIDITY_SECONDS = 60 * 60 * 24 * 60;

    @Autowired
    public AuthorizationServerConfig(AuthenticationManager authenticationManagerBean, PasswordEncoder passwordEncoder, CustomTokenEnhancer customTokenEnhancer, TokenStore tokenStore, JwtAccessTokenConverter accessTokenConverter) {
        this.authenticationManagerBean = authenticationManagerBean;
        this.passwordEncoder = passwordEncoder;
        this.customTokenEnhancer = customTokenEnhancer;
        this.tokenStore = tokenStore;
        this.accessTokenConverter = accessTokenConverter;
    }

    private AuthenticationManager authenticationManagerBean;
    private PasswordEncoder passwordEncoder;
    private CustomTokenEnhancer customTokenEnhancer;
    private JwtAccessTokenConverter accessTokenConverter;
    private TokenStore tokenStore;

    @Override
    public void configure(AuthorizationServerSecurityConfigurer authorizationServerSecurityConfigurer) {
        authorizationServerSecurityConfigurer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clientDetailsServiceConfigurer) throws Exception {

        clientDetailsServiceConfigurer.inMemory().withClient("someclient")
                .authorizedGrantTypes("password", "refresh_token")
                .scopes("read", "write").accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS)
                .refreshTokenValiditySeconds(REFRESH_TOKEN_VALIDITY_SECONDS)
                .secret(this.passwordEncoder.encode("somepassword"));
    }

    @Override
    public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(customTokenEnhancer, accessTokenConverter));
        endpoints.tokenStore(tokenStore).tokenEnhancer(tokenEnhancerChain)
            .authenticationManager(this.authenticationManagerBean);
    }
}

奇怪的是,这似乎是一个谎言,或者是在谈论其他事情,因为当我尝试使用用户名和密码登录时,它可以工作,并且我同时获得刷新和访问令牌。调试器显示s.c.a.w.c.WebSecurityConfigurerAdapter$3 : No authenticationProviders and no parentAuthenticationManager defined. Returning null. 拥有我的自定义身份验证提供程序类,并将它们用于身份验证。

但是,当我尝试使用刷新令牌检索新令牌时,调试器显示该应用似乎采用了不同的ProviderManager路径-该ProviderManager仅具有ProviderManager在其列表中,并且该提供程序不是我配置的提供程序。该PreAuthenticatedAuthenticationProvider试图从PreAuthenticatedAuthenticationProvider检索UserDetailsService,结果是错误:

WebSecurityConfigurerAdapter$UserDetailsServiceDelegator

那么,我缺少什么配置步骤?为什么刷新令牌调用转到其他地方?我要传递的2019-06-08 13:27:24.764 ERROR 8731 --- [nio-8080-exec-3] o.s.s.o.provider.endpoint.TokenEndpoint : Handling error: IllegalStateException, UserDetailsService is required. authenticationManagerBean吗?

0 个答案:

没有答案