2017-03-24 4 views
1

내 응용 프로그램에 대해 OAuth2 인증을 구성하려고합니다. 내가 가진 다음 구성 :왜 AuthenticationCredentialsNotFoundException을 얻고 있습니까?

@Configuration 
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true) 
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration { 

    @Override 
    protected MethodSecurityExpressionHandler createExpressionHandler() { 
     return new OAuth2MethodSecurityExpressionHandler(); 
    } 

} 

@Configuration 
@EnableAuthorizationServer 
@RequiredArgsConstructor(onConstructor = @__(@Autowired)) 
public class OAuth2AuthServerConfig extends AuthorizationServerConfigurerAdapter { 

    private static final String[] GRANT_TYPES = {"password", "refresh_token"}; 
    private static final String[] SCOPES = {"read", "write"}; 

    private final SecurityConfigurationProperties securityConfigurationProperties; 

    private final AuthenticationProvider authenticationProvider; 

    private final OAuth2AccessTokenRepository oAuth2AccessTokenRepository; 
    private final OAuth2RefreshTokenRepository oAuth2RefreshTokenRepository; 

    @Override 
    public void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception { 
     oauthServer 
       .tokenKeyAccess("permitAll()") 
       .checkTokenAccess("isAuthenticated()"); 
    } 

    @Override 
    public void configure(final ClientDetailsServiceConfigurer clients) throws Exception { 
     clients.inMemory() 
       .withClient(securityConfigurationProperties.getClientId()) 
       .authorizedGrantTypes(GRANT_TYPES) 
       .authorities(UserRole.USER.getName()) 
       .scopes(SCOPES) 
       .secret(securityConfigurationProperties.getClientSecret()) 
       .accessTokenValiditySeconds(securityConfigurationProperties.getAccessTokenTime()) 
       .refreshTokenValiditySeconds(securityConfigurationProperties.getRefreshTokenTime()); 
    } 

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

    @Bean 
    public AuthenticationManager authenticationManager() { 
     return new ProviderManager(Collections.singletonList(authenticationProvider)); 
    } 

    @Bean 
    public TokenStore tokenStore() { 
     return new MongoTokenStore(oAuth2AccessTokenRepository, oAuth2RefreshTokenRepository); 
    } 

    @Bean 
    @Primary 
    public DefaultTokenServices tokenServices() { 
     final DefaultTokenServices tokenServices = new DefaultTokenServices(); 
     tokenServices.setTokenStore(tokenStore()); 
     tokenServices.setSupportRefreshToken(true); 
     tokenServices.setAuthenticationManager(authenticationManager()); 

     return tokenServices; 
    } 
} 


@Configuration 
@EnableResourceServer 
@RequiredArgsConstructor(onConstructor = @__(@Autowired)) 
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter { 

    private static final String RESOURCE_ID = "api"; 

    private final TokenStore tokenStore; 

    @Override 
    public void configure(final ResourceServerSecurityConfigurer resources) { 
     resources.resourceId(RESOURCE_ID) 
       .tokenStore(tokenStore); 
    } 

    @Override 
    public void configure(final HttpSecurity http) throws Exception { 
     http.anonymous().disable() 
       .authorizeRequests() 
       .anyRequest().authenticated() 
       .and() 
       .exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler()); 
    } 
} 

@Configuration 
@EnableWebSecurity 
@RequiredArgsConstructor(onConstructor = @__(@Autowired)) 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 

    private final ApiUserDetailsService apiUserDetailsService; 
    private final AuthenticationProvider authenticationProvider; 

    @Override 
    protected void configure(final AuthenticationManagerBuilder auth) throws Exception { 
     auth.authenticationProvider(authenticationProvider); 
    } 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http.csrf().disable() 
       .anonymous().disable() 
       .authorizeRequests() 
       .antMatchers("/").authenticated(); 
    } 
} 

또한 나는 내 사용자 지정 AuthenticationProvider 있습니다

@Service 
@RequiredArgsConstructor(onConstructor = @__(@Autowired)) 
public class UserAuthenticationProvider implements AuthenticationProvider { 

    private final UserRepository userRepository; 
    private final PasswordEncoder passwordEncoder; 

    @Override 
    public Authentication authenticate(final Authentication authentication) 
      throws AuthenticationException { 
     final String email = authentication.getName(); 
     final String password = authentication.getCredentials().toString(); 

     return userRepository.findByEmail(email) 
       .filter(user -> passwordEncoder.matches(password, user.getPassword())) 
       .map(this::signInUser) 
       .orElseThrow(() -> new BadCredentialsException("Failed to authenticate")); 
    } 

    @Override 
    public boolean supports(final Class<?> authentication) { 
     return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication); 
    } 

    private Authentication signInUser(final User user) { 
     final ApiUser springSecurityUser = 
       new ApiUser(user.getEmail(), user.getPassword(), user.getRoles()); 
     final Authentication authentication = new UsernamePasswordAuthenticationToken(springSecurityUser, 
         user.getId(), springSecurityUser.getAuthorities()); 

     SecurityContextHolder.getContext().setAuthentication(authentication); 

     return authentication; 
    } 
} 

모두 내가 액세스 얻고 토큰 작동하고 토큰을 새로 고침을/OAuth를/토큰 엔드 포인트,하지만 때 나 '에서 리소스에 액세스하려는 중입니다. @PreAuthorize annotation 오류가 발생했습니다. 그것은 http://localhost:8080/users/me?access_token=8450e2f3-2ecb-4e88-b304-685b22c2ad65에 대한

링크는 내가 헤더

{ 
    "timestamp": 1490358162182, 
    "status": 403, 
    "error": "Forbidden", 
    "exception": "org.springframework.security.authentication.AuthenticationCredentialsNotFoundException", 
    "message": "Access Denied", 
    "path": "https://stackoverflow.com/users/me" 
} 

의 엔드 포인트를 "Authorization: Bearer 8450e2f3-2ecb-4e88-b304-685b22c2ad65"를 추가하려고했습니다

@PreAuthorize("hasRole('ROLE_USER')") 
@RequestMapping(value = RestPath.Users.ME, method = RequestMethod.GET, 
     produces = MediaType.APPLICATION_JSON_UTF8_VALUE) 
public ResponseEntity userInfo() { 
    return ResponseEntity.noContent().build(); 
} 

아마 누군가가 같은 구성으로 이미 예외를했다.

답변

1

그래, 구성상의 주요 문제는 SecurityConfiguration 클래스에있었습니다. 이 게시물 https://stackoverflow.com/a/42836521/2055854에 따라 특수 효과 @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)을 추가했습니다.

@Configuration 
@EnableWebSecurity 
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) 
@RequiredArgsConstructor(onConstructor = @__(@Autowired)) 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 

    @Autowired 
    private AuthenticationProvider authenticationProvider; 

    @Override 
    protected void configure(final AuthenticationManagerBuilder auth) throws Exception { 
     auth.authenticationProvider(authenticationProvider); 
    } 
} 

그리고 나는 또한 약간 내 구성을 변경했습니다 : 는 이제 보이는 예상대로

@Configuration 
public class OAuth2Config { 

    @Configuration 
    @EnableResourceServer 
    @RequiredArgsConstructor(onConstructor = @__(@Autowired)) 
    public static class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter { 

     public static final String RESOURCE_ID = "api"; 

     private static final String AUTHORIZATION = "Authorization"; 
     private static final String BEARER = "Bearer"; 
     private static final String ACCESS_TOKEN = "access_token"; 

     private final TokenStore tokenStore; 

     @Override 
     public void configure(final ResourceServerSecurityConfigurer resources) { 
      resources.resourceId(RESOURCE_ID) 
        .tokenStore(tokenStore); 
     } 

     @Override 
     public void configure(final HttpSecurity http) throws Exception { 
      http.csrf().disable() 
        .authorizeRequests().anyRequest().permitAll() 
        .and() 
        .sessionManagement() 
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS) 
        .and() 
        .exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler()); 
     } 
    } 


    @Configuration 
    @EnableAuthorizationServer 
    @RequiredArgsConstructor(onConstructor = @__(@Autowired)) 
    public static class OAuth2AuthServerConfig extends AuthorizationServerConfigurerAdapter { 

     private static final String[] GRANT_TYPES = {"password", "refresh_token"}; 
     private static final String[] SCOPES = {"read", "write"}; 

     private final SecurityConfigurationProperties securityConfigurationProperties; 

     private final AccessTokenRepository oAuth2AccessTokenRepository; 
     private final RefreshTokenRepository oAuth2RefreshTokenRepository; 

     private final AuthenticationProvider authenticationProvider; 
     private final UserDetailsService userDetailsService; 

     @Override 
     public void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception { 
      oauthServer 
        .tokenKeyAccess("permitAll()") 
        .checkTokenAccess("isAuthenticated()"); 
     } 

     @Override 
     public void configure(final ClientDetailsServiceConfigurer clients) throws Exception { 
      clients.inMemory() 
        .withClient(securityConfigurationProperties.getClientId()) 
        .authorizedGrantTypes(GRANT_TYPES) 
        .authorities(UserRole.USER.getName()) 
        .secret(securityConfigurationProperties.getClientSecret()) 
        .scopes(SCOPES) 
        .resourceIds(OAuth2ResourceServerConfig.RESOURCE_ID) 
        .accessTokenValiditySeconds(securityConfigurationProperties.getAccessTokenTime()) 
        .refreshTokenValiditySeconds(securityConfigurationProperties.getRefreshTokenTime()); 
     } 

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

     public AuthenticationManager authenticationManager() { 
      return new ProviderManager(Collections.singletonList(authenticationProvider)); 
     } 

     @Bean 
     public TokenStore tokenStore() { 
      return new MongoTokenStore(oAuth2AccessTokenRepository, oAuth2RefreshTokenRepository); 
     } 

     @Bean 
     @Primary 
     public DefaultTokenServices tokenServices() { 
      final DefaultTokenServices tokenServices = new DefaultTokenServices(); 
      tokenServices.setTokenStore(tokenStore()); 
      tokenServices.setSupportRefreshToken(true); 
      tokenServices.setAuthenticationManager(authenticationManager()); 

      return tokenServices; 
     } 
    } 
} 

이제 모든 작품을.