【问题标题】:spring custom mongo TokenStore not refresh new access_token automatically when old expired?spring custom mongo TokenStore在旧的过期时不会自动刷新新的access_token?
【发布时间】:2017-04-11 07:10:44
【问题描述】:

我使用 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;
        }

    }
}

问题是:

我可以通过“authorization_code”从spring zuul ui-server登录,并且可以 访问 ResourceServer 数据。

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

如何解决?

【问题讨论】:

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


    【解决方案1】:

    刷新令牌的全部意义在于为 OAuth2 增加一个安全维度。

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

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

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

    因此,总而言之,您有责任确保您的最终用户再次通过 OAuth2 重新授权。

    您也可以阅读:

    Why Does OAuth v2 Have Both Access and Refresh Tokens?

    【讨论】:

    • 谢谢你的回答,我知道规则,你能给我一些关于如何使用自定义 MongoTokenStore (authorization_code 授权类型) 实现的建议
    猜你喜欢
    • 2023-03-08
    • 1970-01-01
    • 2019-05-09
    • 2018-08-05
    • 2015-09-10
    • 2021-10-22
    • 2018-12-25
    • 1970-01-01
    • 2018-01-02
    相关资源
    最近更新 更多