spring custom mongo TokenStore在旧的过期时自动刷新新的access_token?

时间:2016-11-27 13:23:04

标签: spring spring-cloud spring-security-oauth2 spring-oauth2 spring-mongodb

我使用mongo自定义tokenStore和codeService:

这是我自定义的mongoTokenStore:

public class MongoTokenStore implements TokenStore {

    private final MongoAccessTokenRepository mongoAccessTokenRepository;
    private final MongoRefreshTokenRepository mongoRefreshTokenRepository;
    private AuthenticationKeyGenerator authenticationKeyGenerator =
            new DefaultAuthenticationKeyGenerator();

    public MongoTokenStore(MongoAccessTokenRepository mongoAccessTokenRepository, MongoRefreshTokenRepository mongoRefreshTokenRepository) {
        this.mongoAccessTokenRepository = mongoAccessTokenRepository;
        this.mongoRefreshTokenRepository = mongoRefreshTokenRepository;
    }


    @Override
    public OAuth2Authentication readAuthentication(OAuth2AccessToken oAuth2AccessToken) {
        return readAuthentication(oAuth2AccessToken.getValue());
    }

    @Override
    public OAuth2Authentication readAuthentication(String tokenId) {
        return mongoAccessTokenRepository.findByTokenId(tokenId)
                .map(MongoAccessToken::getAuthentication)
                .orElse(null);
    }

    @Override
    public void storeAccessToken(OAuth2AccessToken oAuth2AccessToken, OAuth2Authentication oAuth2Authentication) {

        MongoAccessToken mongoAccessToken = new MongoAccessToken(oAuth2AccessToken, oAuth2Authentication,
                authenticationKeyGenerator.extractKey(oAuth2Authentication));
        mongoAccessTokenRepository.save(mongoAccessToken);
    }

    @Override
    public OAuth2AccessToken readAccessToken(String tokenValue) {
        return mongoAccessTokenRepository.findByTokenId(tokenValue)
                .map(MongoAccessToken::getOAuth2AccessToken)
                .orElse(null);
    }

    @Override
    public void removeAccessToken(OAuth2AccessToken oAuth2AccessToken) {
        mongoAccessTokenRepository.findByTokenId(oAuth2AccessToken.getValue())
                .ifPresent(mongoAccessTokenRepository::delete);
    }

    @Override
    public void storeRefreshToken(OAuth2RefreshToken oAuth2RefreshToken, OAuth2Authentication oAuth2Authentication) {
        MongoRefreshToken token=new MongoRefreshToken(oAuth2RefreshToken,oAuth2Authentication);
        mongoRefreshTokenRepository.save(token);

    }

    @Override
    public OAuth2RefreshToken readRefreshToken(String tokenValue) {
        return mongoRefreshTokenRepository.findByTokenId(tokenValue)
                .map(MongoRefreshToken::getOAuth2RefreshToken)
                .orElse(null);
    }

    @Override
    public OAuth2Authentication readAuthenticationForRefreshToken(OAuth2RefreshToken oAuth2RefreshToken) {

        return mongoRefreshTokenRepository.findByTokenId(oAuth2RefreshToken.getValue())
                .map(MongoRefreshToken::getAuthentication)
                .orElse(null);
    }

    @Override
    public void removeRefreshToken(OAuth2RefreshToken oAuth2RefreshToken) {
        mongoRefreshTokenRepository.findByTokenId(oAuth2RefreshToken.getValue())
                .ifPresent(mongoRefreshTokenRepository::delete);
    }

    @Override
    public void removeAccessTokenUsingRefreshToken(OAuth2RefreshToken oAuth2RefreshToken) {

        mongoAccessTokenRepository.findByRefreshToken(oAuth2RefreshToken.getValue())
                .ifPresent(mongoAccessTokenRepository::delete);
    }

    @Override
    public OAuth2AccessToken getAccessToken(OAuth2Authentication oAuth2Authentication) {

        return mongoAccessTokenRepository.findByAuthenticationId(authenticationKeyGenerator
                .extractKey(oAuth2Authentication))
                .map(MongoAccessToken::getOAuth2AccessToken)
                .orElse(null);
    }

    @Override
    public Collection<OAuth2AccessToken> findTokensByClientIdAndUserName(String s, String s1) {

        return mongoAccessTokenRepository.findByClientIdAndUserName(s,s1)
                .stream()
                .map(MongoAccessToken::getOAuth2AccessToken)
                .collect(Collectors.toList());
    }

    @Override
    public Collection<OAuth2AccessToken> findTokensByClientId(String s) {
        return mongoAccessTokenRepository.findByClientId(s)
                .stream()
                .map(MongoAccessToken::getOAuth2AccessToken)
                .collect(Collectors.toList());
    }
}

这是我的自定义mongoCodeService:

@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class MongoAuthenticationCodeService extends RandomValueAuthorizationCodeServices{

    private final MongoAuthenticationCodeRepository repository;

    @Override
    protected void store(String code, OAuth2Authentication oAuth2Authentication) {

        repository.save(new MongoAuthenticationCode(code,oAuth2Authentication));
    }

    @Override
    protected OAuth2Authentication remove(String code) {

        return repository.findOneByCode(code)
                .map(MongoAuthenticationCode::getAuthentication)
                .orElse(null);
    }
}

和我的OAuth2Config:

@Configuration
public class OAuth2ServerConfiguration {

    @Configuration
    @EnableResourceServer
    protected static class ResourceServerConfiguration extends
            ResourceServerConfigurerAdapter {

        @Override
        public void configure(ResourceServerSecurityConfigurer resources) {
            resources.resourceId(READ_AND_WRITE_RESOURCE_ID);
        }

        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    .antMatchers("/webjars/**", "/oauth/authorize/**", "/", "/customLogout",
                            "/oauth/check_token/**", "/login").permitAll()
                    .mvcMatchers(HttpMethod.GET, "/loginAttemptUsers").hasRole("ADMIN")
                    .anyRequest().authenticated();
        }

    }

    @Configuration
    @EnableAuthorizationServer
    protected static class AuthorizationServerConfiguration extends
            AuthorizationServerConfigurerAdapter {

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


        @Autowired
        private CustomUserDetailService customUserDetailService;

        @Autowired
        private MongoAuthenticationCodeService mongoAuthenticationCodeService;

        @Autowired
        private MongoTokenStore mongoTokenStore;

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints)
                throws Exception {

            endpoints
                    .authorizationCodeServices(mongoAuthenticationCodeService)
                    .tokenStore(mongoTokenStore)
                    .authenticationManager(authenticationManager)
                    .userDetailsService(customUserDetailService)
                    .approvalStoreDisabled();

        }

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

            clients
                    .inMemory()
                    .withClient("kksdi2388wmkwe")
                    .authorizedGrantTypes("authorization_code", "password", "refresh_token")
                    .scopes("read", "write")
                    .resourceIds("ReadAndWriteResource")
                    .secret("kksd23isdmsisdi2")
                    .autoApprove(true)
                    .accessTokenValiditySeconds(120)
                    .refreshTokenValiditySeconds(1200);

        }

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

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

    }
}
问题是:

我可以通过&#34; authorization_code&#34;从spring zuul ui-server登录,并且可以   访问ResourceServer数据。

但是当access_token过期(120s)时,在重新获取ResourceServer数据时,我看到mongoTokenStore删除了现有的access_token,但是为什么不自动刷新新的access_token

如何解决?

1 个答案:

答案 0 :(得分:0)

刷新令牌的重点是向OAuth2添加一个安全维度。

当最终用户获得访问令牌时,他现在可以访问令牌授予他的授权规则中的任何资源。

如果他的访问令牌以某种方式被盗,攻击者现在可以访问访问令牌授权他的任何资源,但是如果我们设置访问令牌的到期时间,则攻击者将具有有限的访问时间。

话虽如此,如果spring oauth2会自动刷新该令牌,那么将不再应用一个安全方面,并且整个令牌刷新的想法将被浪费。

因此,最后要确保您的最终用户再次通过OAuth2重新授权。

您还可以阅读:

Why Does OAuth v2 Have Both Access and Refresh Tokens?