2016-09-22 106 views
1

在我的春節,啓動應用程序,我想配置Spring的OAuth2 +智威湯遜春天啓動的OAuth2 +智威湯遜和UserDetailsS​​ervice的

這是我OAuth2ServerConfig配置:

@Configuration 
public class OAuth2ServerConfig { 

    private static final String RESOURCE_ID = "restservice"; 

    @Bean 
    @Primary 
    public DefaultTokenServices tokenServices() { 
     DefaultTokenServices defaultTokenServices = new DefaultTokenServices(); 
     defaultTokenServices.setTokenStore(tokenStore()); 
     defaultTokenServices.setSupportRefreshToken(true); 
     return defaultTokenServices; 
    } 

    @Bean 
    public JwtAccessTokenConverter accessTokenConverter() { 
     JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); 
     converter.setSigningKey("123"); 
     return converter; 
    } 

    @Bean 
    public TokenStore tokenStore() { 
     return new JwtTokenStore(accessTokenConverter()); 
    } 

    @Configuration 
    @EnableAuthorizationServer 
    protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter { 

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

     @Autowired 
     private TokenStore tokenStore; 

     @Autowired 
     private TokenEnhancer tokenEnhancer; 

     @Override 
     public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { 
      // @formatter:off 
      endpoints 
       .tokenStore(tokenStore) 
       .tokenEnhancer(tokenEnhancer) 
       .authenticationManager(this.authenticationManager); 
      // @formatter:on 
     } 

     @Override 
     public void configure(ClientDetailsServiceConfigurer clients) throws Exception { 
      // @formatter:off 
      clients 
       .inMemory() 
        .withClient("clientapp") 
         .authorizedGrantTypes("password","refresh_token") 
         .authorities("ROLE_CLIENT") 
         .scopes("read", "write") 
         .resourceIds(RESOURCE_ID) 
         .secret("123456"); 
      // @formatter:on 
     } 

    } 

    @Configuration 
    @EnableResourceServer 
    protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter { 

     @Autowired 
     private ResourceServerTokenServices tokenService; 

     @Override 
     public void configure(ResourceServerSecurityConfigurer resources) { 
      // @formatter:off 
      resources   
       .resourceId(RESOURCE_ID) 
       .tokenServices(tokenService); 
      // @formatter:on 
     } 

     @Override 
     public void configure(HttpSecurity http) throws Exception { 
      // @formatter:off 
      http 
       .authorizeRequests() 
        .antMatchers("/profile/*").authenticated() 
        .and().csrf() 
        .disable().sessionManagement().sessionCreationPolicy(STATELESS); 
      // @formatter:on 
     } 

    } 

} 

這是我UserDetailsService實現:

@Service 
public class DBUserDetailsService implements UserDetailsService { 

    @Autowired 
    private UserService userService; 

    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 
     User user = userService.findUserByUsername(username); 
     if (user == null) { 
      throw new UsernameNotFoundException("User " + username + " not found."); 
     } 

     Set<Permission> permissions = userService.getUserPermissions(user); 
     return new DBUserDetails(user, permissions); 
    } 

} 

這是WebSecurityConfig

@Configuration 
@EnableWebSecurity 
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 

    @Autowired 
    private SocialAuthenticationSuccessHandler socialAuthenticationSuccessHandler; 

    @Autowired 
    private DBUserDetailsService userDetailsService; 

    @Value("${social.postLogin.url}") 
    private String postLoginUrl; 

    @Override 
    public void configure(WebSecurity web) throws Exception { 
     // Spring Security ignores request to static resources such as CSS or JS 
     // files. 
     web.ignoring().antMatchers("/static/**"); 
    } 


    @Override 
    protected void configure(HttpSecurity http) throws Exception { 

     // @formatter:off 
     http.addFilterBefore(new CorsFilter(), ChannelProcessingFilter.class); 

     // Set a custom successHandler on the SocialAuthenticationFilter 
     final SpringSocialConfigurer socialConfigurer = new SpringSocialConfigurer(); 
     socialConfigurer.addObjectPostProcessor(new ObjectPostProcessor<SocialAuthenticationFilter>() { 
      @Override 
      public <O extends SocialAuthenticationFilter> O postProcess(O socialAuthenticationFilter) { 
       socialAuthenticationFilter.setAuthenticationSuccessHandler(socialAuthenticationSuccessHandler); 
       socialAuthenticationFilter.setPostLoginUrl(postLoginUrl); 
       return socialAuthenticationFilter; 
      } 
     }); 

     http.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) 
     //Configures url based authorization 
     .and() 
      .authorizeRequests() 
      //Anyone can access the urls 
      .antMatchers("/auth/**").permitAll() 
      .antMatchers("/actuator/health").permitAll() 
      .antMatchers("/actuator/**").hasAuthority("PERMISSION_READ_ACTUATOR_DATA") 
     //Adds the SocialAuthenticationFilter to Spring Security's filter chain. 
     .and() 
      // apply the configuration from the socialConfigurer (adds the SocialAuthenticationFilter) 
      .apply(socialConfigurer); 

     // @formatter:on 
    } 

    /** 
    * Configures the authentication manager bean which processes authentication 
    * requests. 
    */ 
    @Override 
    protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
     auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder()); 
    } 

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

} 

現在我能夠成功發行JWT的accessToken但是當我嘗試使用它,我現有的邏輯失敗,出現以下錯誤:

java.lang.String cannot be cast to com.example.domain.model.security.DBUserDetails 

對於某些原因,DBUserDetailsService.loadUserByUsername成功後,則不會調用身份驗證基於JWT令牌,而不是DBUserDetailsSecurityContextHolder.getContext().getAuthentication().getPrincipal()我只有一個字符串,用戶名如「admin」

我在做什麼錯?

+0

據我所知,沒有什麼。看起來像委託人設置正確。你還期望'Authentication'對象有什麼? –

+0

我期望DBUserDetails對象(在DBUserDetailsS​​ervice.loadUserByUsername方法調用之後)像使用純粹的OAuth2配置而不使用JWT令牌 – alexanoid

回答

1

Spring源代碼調試後我發現一個解決方案如何將我的UserDetailsService注入流中。爲了做到這一點,你必須修改accessTokenConverter()方法:

@Autowired 
private DBUserDetailsService userDetailsService; 

@Bean 
public JwtAccessTokenConverter accessTokenConverter() { 
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); 
    converter.setSigningKey("123"); 

    DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter(); 
    DefaultUserAuthenticationConverter userTokenConverter = new DefaultUserAuthenticationConverter(); 
    userTokenConverter.setUserDetailsService(userDetailsService); 
    accessTokenConverter.setUserTokenConverter(userTokenConverter); 

    converter.setAccessTokenConverter(accessTokenConverter); 

    return converter; 
}