Spring oidc 的安全性:刷新令牌
Spring Security with oidc: refresh the tokens
Spring Boot 2 with Spring Security 5 可以配置为使用 openID 连接 ID 提供程序进行身份验证。
我仅通过配置 Spring 安全性就设法设置了我的项目 - 这适用于各种完美预配置的安全机制,例如缓解会话固定。
但似乎 Spring 安全性在令牌过期时不会自行刷新令牌(存储在会话中)。
是否有相应的设置,还是我必须自己进行刷新?
更新: Spring Boot 2.1 已经发布,是时候重新审视这个问题了。我仍然不知道 accessToken 现在是否可以自动刷新,或者我是否必须为此编写代码...
即使是 100 点的赏金也没有得到答案。所以我想目前还没有实现自动刷新访问令牌的机制 Spring Security.
一个有效的替代方案似乎是使用 spring boot keycloak 适配器,它能够刷新令牌。
根据文档,
https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#webclient
使用正确配置的 WebClient 时,如文档中所述,它将自动刷新。
Spring Security will automatically refresh expired tokens (if a refresh token is present)
支持刷新令牌的功能矩阵也支持这一点。
https://github.com/spring-projects/spring-security/wiki/OAuth-2.0-Features-Matrix
Spring Security 5 上有一个较旧的博客,它使您可以访问 bean,您可以手动执行此操作,
Authentication authentication =
SecurityContextHolder
.getContext()
.getAuthentication();
OAuth2AuthenticationToken oauthToken =
(OAuth2AuthenticationToken) authentication;
There will be an OAuth2AuthorizedClientService automatically configured as a bean in the Spring application context, so you’ll only need to inject it into wherever you’ll use it.
OAuth2AuthorizedClient client =
clientService.loadAuthorizedClient(
oauthToken.getAuthorizedClientRegistrationId(),
oauthToken.getName());
String refreshToken = client.getRefreshToken();
而且,现在找不到它,但我认为作为 OAuth2AuthorizedClientExchangeFilterFunction
的一部分,有调用进行刷新。
根据 https://github.com/spring-projects/spring-security/issues/6742 看来令牌是故意不刷新的:
An ID Token typically comes with an expiration date. The RP MAY
rely on it to expire the RP session.
Spring 没有。最后提到了两个增强功能,应该可以解决一些刷新问题 - 两者都仍然开放。
作为解决方法,我实施了一个 GenericFilterBean,它检查令牌并清除当前安全上下文中的身份验证。因此需要一个新的令牌。
@Configuration
public class RefreshTokenFilterConfig {
@Bean
GenericFilterBean refreshTokenFilter(OAuth2AuthorizedClientService clientService) {
return new GenericFilterBean() {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication instanceof OAuth2AuthenticationToken) {
OAuth2AuthenticationToken token = (OAuth2AuthenticationToken) authentication;
OAuth2AuthorizedClient client =
clientService.loadAuthorizedClient(
token.getAuthorizedClientRegistrationId(),
token.getName());
OAuth2AccessToken accessToken = client.getAccessToken();
if (accessToken.getExpiresAt().isBefore(Instant.now())) {
SecurityContextHolder.getContext().setAuthentication(null);
}
}
filterChain.doFilter(servletRequest, servletResponse);
}
};
}
}
此外,我必须将过滤器添加到安全配置中:
@Bean
public WebSecurityConfigurerAdapter webSecurityConfigurer(GenericFilterBean refreshTokenFilter) {
return new WebSecurityConfigurerAdapter() {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(refreshTokenFilter, AnonymousAuthenticationFilter.class)
在 2.2 版中使用 spring-boot-starter-parent 和依赖项实现。7.RELEASE:
- spring-boot-starter-web
- spring-boot-starter-security
- spring-boot-starter-oauth2-client
我很欣赏关于此解决方法的意见,因为我仍然不确定 Spring Boot 中是否真的需要这样的开销。
Spring Boot 2 with Spring Security 5 可以配置为使用 openID 连接 ID 提供程序进行身份验证。 我仅通过配置 Spring 安全性就设法设置了我的项目 - 这适用于各种完美预配置的安全机制,例如缓解会话固定。
但似乎 Spring 安全性在令牌过期时不会自行刷新令牌(存储在会话中)。
是否有相应的设置,还是我必须自己进行刷新?
更新: Spring Boot 2.1 已经发布,是时候重新审视这个问题了。我仍然不知道 accessToken 现在是否可以自动刷新,或者我是否必须为此编写代码...
即使是 100 点的赏金也没有得到答案。所以我想目前还没有实现自动刷新访问令牌的机制 Spring Security.
一个有效的替代方案似乎是使用 spring boot keycloak 适配器,它能够刷新令牌。
根据文档,
https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#webclient
使用正确配置的 WebClient 时,如文档中所述,它将自动刷新。
Spring Security will automatically refresh expired tokens (if a refresh token is present)
支持刷新令牌的功能矩阵也支持这一点。
https://github.com/spring-projects/spring-security/wiki/OAuth-2.0-Features-Matrix
Spring Security 5 上有一个较旧的博客,它使您可以访问 bean,您可以手动执行此操作,
Authentication authentication =
SecurityContextHolder
.getContext()
.getAuthentication();
OAuth2AuthenticationToken oauthToken =
(OAuth2AuthenticationToken) authentication;
There will be an OAuth2AuthorizedClientService automatically configured as a bean in the Spring application context, so you’ll only need to inject it into wherever you’ll use it.
OAuth2AuthorizedClient client =
clientService.loadAuthorizedClient(
oauthToken.getAuthorizedClientRegistrationId(),
oauthToken.getName());
String refreshToken = client.getRefreshToken();
而且,现在找不到它,但我认为作为 OAuth2AuthorizedClientExchangeFilterFunction
的一部分,有调用进行刷新。
根据 https://github.com/spring-projects/spring-security/issues/6742 看来令牌是故意不刷新的:
An ID Token typically comes with an expiration date. The RP MAY rely on it to expire the RP session.
Spring 没有。最后提到了两个增强功能,应该可以解决一些刷新问题 - 两者都仍然开放。
作为解决方法,我实施了一个 GenericFilterBean,它检查令牌并清除当前安全上下文中的身份验证。因此需要一个新的令牌。
@Configuration
public class RefreshTokenFilterConfig {
@Bean
GenericFilterBean refreshTokenFilter(OAuth2AuthorizedClientService clientService) {
return new GenericFilterBean() {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication instanceof OAuth2AuthenticationToken) {
OAuth2AuthenticationToken token = (OAuth2AuthenticationToken) authentication;
OAuth2AuthorizedClient client =
clientService.loadAuthorizedClient(
token.getAuthorizedClientRegistrationId(),
token.getName());
OAuth2AccessToken accessToken = client.getAccessToken();
if (accessToken.getExpiresAt().isBefore(Instant.now())) {
SecurityContextHolder.getContext().setAuthentication(null);
}
}
filterChain.doFilter(servletRequest, servletResponse);
}
};
}
}
此外,我必须将过滤器添加到安全配置中:
@Bean
public WebSecurityConfigurerAdapter webSecurityConfigurer(GenericFilterBean refreshTokenFilter) {
return new WebSecurityConfigurerAdapter() {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(refreshTokenFilter, AnonymousAuthenticationFilter.class)
在 2.2 版中使用 spring-boot-starter-parent 和依赖项实现。7.RELEASE:
- spring-boot-starter-web
- spring-boot-starter-security
- spring-boot-starter-oauth2-client
我很欣赏关于此解决方法的意见,因为我仍然不确定 Spring Boot 中是否真的需要这样的开销。