1

SpringSecurityFilterチェーンは、インバウンドリクエストスレッドで実行され、別のスレッドで実行される非同期コードに渡されるため、@Asyncリクエストのリクエストごとに2回実行されます。応答スレッドに書き込みを試みると、SpringSecurityFilterチェーンが再び実行されます。async要求によるスプリングセキュリティoauth2の使用

これは、RemoteTokenServicesを使用しているため、access_tokenの有効期限近くに問題が発生しています。元の要求が認証され、サービスアクティビティが約1秒かかると、RemoteTokenServicesが再び呼び出されます。その時点でaccess_tokenは期限切れですそのリクエストは401を返します。

ここで推奨される解決策は何ですか?私は、SecurityFilterChainが応答スレッドで2回目の実行を妨げることができませんでした。間違ったことをやっているのですか?私はSecurityContextが@Asyncスレッドに正しく渡されているのを見ますが、応答スレッドではnullです。

SecurityFilterChainが要求ごとに1回だけ実行されるようにする方法はありますか?または、リクエストごとに複数のフィルタ呼び出しを受け入れ、何とかキャッシュして処理するソリューションですか?

私はspring-boot 1.3.3.RELEASEとspring-security-oauth2 2.0.9.RELEASEを使用しています。

ログ:

INFO [..nio-exec-1] [Caching...] loadAuthentication: 0bc97f92-9ebb-411f-9e8e-e7dc137aeffe 
DEBUG [..nio-exec-1] [Caching...] Entering CachingRemoteTokenService auth: null 
DEBUG [..nio-exec-1] [Audit...] AuditEvent [timestamp=Wed Mar 30 12:27:45 PDT 2016, principal=testClient, type=AUTHENTICATION_SUCCESS, data={details=remoteAddress=127.0.0.1, tokenType=BearertokenValue=<TOKEN>}] 
INFO [..nio-exec-1] [Controller] Callable testing request received 
DEBUG [MvcAsync1] [TaskService] taskBegin 
DEBUG [MvcAsync1] [TaskService] Entering TaskService auth: or[email protected]47c78d1a: Principal: testClient; Credentials: [PROTECTED]; Authenticated: true; Details: remoteAddress=127.0.0.1, tokenType=BearertokenValue=<TOKEN>; Granted Authorities: ROLE_CLIENT 
DEBUG [MvcAsync1] [TaskService] end of task 
INFO [..nio-exec-2] [Caching...] loadAuthentication: 0bc97f92-9ebb-411f-9e8e-e7dc137aeffe 
DEBUG [..nio-exec-2] [Caching...] Entering CachingRemoteTokenService auth: null 
DEBUG [..nio-exec-2] [RemoteTokenServices] check_token returned error: invalid_token 
DEBUG [..nio-exec-2] [Audit...] AuditEvent [timestamp=Wed Mar 30 12:27:47 PDT 2016, principal=access-token, type=AUTHENTICATION_FAILURE, data={type=org.springframework.security.authentication.BadCredentialsException, message=0bc97f92-9ebb-411f-9e8e-e7dc137aeffe}] 

関連コード:

コントローラ:

@RequestMapping(value = "/callable", 
method = RequestMethod.GET, 
produces = { MediaType.APPLICATION_JSON_VALUE }) 
public @ApiResponseObject Callable<ApiResponse> runCallable(HttpServletRequest httpServletRequest) 
     throws InterruptedException { 
    log.info(String.format("Callable testing request received")); 
    Callable<ApiResponse> rv = taskService::execute; 
    return rv; 
} 

非同期サービス:

@Override 
public ApiResponse execute() { 
    log.debug("taskBegin"); 
    Authentication auth = SecurityContextHolder.getContext().getAuthentication(); 
    log.debug("Entering TaskService auth: " + auth); 
    try { 
     Thread.sleep(1000); 
    } catch (InterruptedException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    ApiResponse rv = new ApiResponse(); 
    rv.setStatus(HttpStatus.OK.value()); 
    log.debug("end of task"); 
    return rv; 
} 

RemoteTokenServices実装(注キャッシングは、Oコメント化されてUT):

public class CachingRemoteTokenService extends RemoteTokenServices { 

    private static Log log = LogFactory.getLog(CachingRemoteTokenService.class); 

    @Override 
    //@Cacheable(cacheNames="tokens", key="#root.methodName + #accessToken") 
    public OAuth2Authentication loadAuthentication(String accessToken) 
      throws org.springframework.security.core.AuthenticationException, 
        InvalidTokenException { 
     log.info("loadAuthentication: " + accessToken); 
     Authentication auth = SecurityContextHolder.getContext().getAuthentication(); 
     log.debug("Entering CachingRemoteTokenService auth: " + auth); 
     return super.loadAuthentication(accessToken); 
    } 

    @Override 
    //@Cacheable(cacheNames="tokens", key="#root.methodName + #accessToken") 
    public OAuth2AccessToken readAccessToken(String accessToken) { 
     log.info("readAccessToken: " + accessToken); 
     Authentication auth = SecurityContextHolder.getContext().getAuthentication(); 
     log.debug("Entering CachingRemoteTokenService auth: " + auth); 
     return super.readAccessToken(accessToken); 
    } 
} 

、最終的に私のセキュリティ設定:

@Configuration 
public class Oauth2ResourceConfig { 

    private static Log log = LogFactory.getLog(Oauth2ResourceConfig.class); 

    @Value("${client.secret}") 
    private String clientSecret; 

    @Value("${check.token.endpoint}") 
    private String checkTokenEndpoint; 

    @Bean 
    @Lazy 
    public ResourceServerTokenServices tokenService() { 
     CachingRemoteTokenService tokenServices = new CachingRemoteTokenService(); 
     tokenServices.setClientId("test-service"); 
     tokenServices.setClientSecret(clientSecret); 
     tokenServices.setCheckTokenEndpointUrl(checkTokenEndpoint); 

     return tokenServices; 
    } 

    @Configuration 
    @EnableResourceServer 
    protected static class ResourceServerConfig extends ResourceServerConfigurerAdapter { 

     @Override 
     public void configure(HttpSecurity http) throws Exception { 
      http.authorizeRequests() 
       .antMatchers("/health-check").permitAll() 
       .antMatchers("/**").access("#oauth2.isClient() and #oauth2.hasScope('trust')"); 

     @Override 
     public void configure(ResourceServerSecurityConfigurer resources) throws Exception { 
      resources.resourceId("test-service"); 
     } 
    } 
} 

答えて

関連する問題