Spring Boot OAuth 2-истекающий срок действия токенов обновления при смене пароля
Я создал API, используя Spring Boot/OAuth. В настоящее время установлено так, что маркеры доступа действительны в течение 30 дней, и их сроком на 5 лет. Было предложено, чтобы OAuth работал таким образом, чтобы один refresh_token можно было использовать снова и снова. То, что нам также нужно сделать, это реализовать какой-то способ истечения срока действия токенов обновления, когда пользователь меняет свой пароль, это то, с чем я борюсь, поскольку мы не используем хранилище токенов, поскольку мы используем JWTs, поэтому нет необходимости хранить токены, и даже когда мы хранили их в базе данных, мы регулярно получали ошибки "недопустимый токен обновления", поэтому удалили хранилище токенов.
Мой вопрос заключается в том, как вы обрабатываете истекающие токены обновления, скажем, когда пользователь меняет свой пароль (как предлагает OAuth).
Мой клиент специально запросил, чтобы возвращаемый refresh_token был долговечным, но я обеспокоен тем, что маркер обновления с длительным сроком службы не очень безопасен, как будто кто-то получает доступ к этому маркеру, они могут получить доступ к пользователям счет до тех пор, пока этот токен не истечет естественным образом. Лично я бы предпочел установить более короткий срок действия на refresh_tokens, скажем, 45 дней, заставляя клиента хранить новый refresh_token каждые 45 дней, по крайней мере.
Вот некоторые из моих классов конфигурации для безопасности, чтобы показать, как у меня сейчас все настроено;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private Environment env;
@Autowired
private CustomUserDetailsService userDetailsService;
@Autowired
private AccountAuthenticationProvider accountAuthenticationProvider;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
auth.authenticationProvider(accountAuthenticationProvider);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
final JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
jwtAccessTokenConverter.setSigningKey(env.getProperty("jwt.secret"));
return jwtAccessTokenConverter;
}
}
@Configuration
public class OAuth2ServerConfiguration {
private static final String RESOURCE_ID = "myapi";
@Autowired
DataSource dataSource;
@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
@Configuration
@EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Autowired
TokenStore tokenStore;
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources
.resourceId(RESOURCE_ID)
.tokenStore(tokenStore);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/oauth/**", "/view/**").permitAll()
.anyRequest().authenticated();
}
}
@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
@Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;
@Autowired
private DataSource dataSource;
@Autowired
private TokenStore tokenStore;
@Autowired
private CustomUserDetailsService userDetailsService;
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
//.tokenStore(tokenStore)
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService)
.accessTokenConverter(jwtAccessTokenConverter);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.jdbc(dataSource);
}
}
}
1 ответ:
Отзыв токена не поддерживается, если используется JWT. Если вы хотите, чтобы эта функциональность была реализована, вы должны рассмотреть возможность использования JdbcTokenStore вместо этого.
@Bean public TokenStore tokenStore() { return new JdbcTokenStore(dataSource()); } @Bean public DataSource dataSource() { DriverManagerDataSource jdbcdataSource = new DriverManagerDataSource(); jdbcdataSource.setDriverClassName(env.getProperty("jdbc.driverClassName")); jdbcdataSource.setUrl(env.getProperty("jdbc.url"));//connection String jdbcdataSource.setUsername(env.getProperty("jdbc.user")); jdbcdataSource.setPassword(env.getProperty("jdbc.pass")); return dataSource; }Когда пользователь меняет пароль, вы должны вызвать API revokeToken
@Resource(name="tokenServices") ConsumerTokenServices tokenServices; @RequestMapping(method = RequestMethod.POST, value = "/tokens/revoke/{tokenId:.*}") @ResponseBody public String revokeToken(@PathVariable String tokenId) { tokenServices.revokeToken(tokenId); return tokenId; }JDBCTokenStore также предоставляет метод, с помощью которого можно аннулировать маркер обновления
@RequestMapping(method = RequestMethod.POST, value = "/tokens/revokeRefreshToken/{tokenId:.*}") @ResponseBody public String revokeRefreshToken(@PathVariable String tokenId) { if (tokenStore instanceof JdbcTokenStore){ ((JdbcTokenStore) tokenStore).removeRefreshToken(tokenId); } return tokenId; }
Comments