
本文将介绍如何通过 Spring Security 和 JWT(JSON Web Token)来限制刷新令牌只能用于特定的刷新令牌端点,从而增强系统的安全性。通过为访问令牌添加特定的权限,并配置 Spring Security 来强制执行这些权限,可以有效防止刷新令牌被用于访问其他受保护的资源。同时,还会提及关于JWT声明名称配置一致性的重要性。
限制刷新令牌的使用范围
在基于 JWT 的身份验证系统中,刷新令牌的目的是在访问令牌过期后,允许客户端无需重新输入用户名和密码即可获取新的访问令牌。然而,如果刷新令牌可以被用于访问任何受保护的资源,那么短期访问令牌的优势就会大打折扣。为了解决这个问题,我们可以采取以下策略:
- 为访问令牌添加特定权限: 为每个访问令牌添加一个特定的权限,例如 "access"。
- 配置 Spring Security: 配置 Spring Security,要求所有受保护的端点都必须具有 "access" 权限。
- 刷新令牌不包含该权限: 刷新令牌不包含 "access" 权限,因此无法用于访问其他端点。
代码示例
以下是如何在 JwtTokenServiceImpl 类中修改 generateAccessToken 方法,以添加 "access" 权限:
@Override
public String generateAccessToken(User user) {
Instant now = Instant.now();
String scope = user.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(" "));
String accessScope = scope.concat(" access");
JwtClaimsSet claims = JwtClaimsSet.builder()
.issuer("self")
.issuedAt(now)
.expiresAt(now.plus(2, ChronoUnit.MINUTES))
.subject(user.getUsername())
.claim("roles", accessScope)
.build();
return this.jwtEncoder.encode(JwtEncoderParameters.from(claims)).getTokenValue();
}接下来,在 WebSecurityConfig 类中,配置 Spring Security 以要求所有受保护的端点都必须具有 "ROLE_access" 权限:
http.authorizeHttpRequests()
.requestMatchers("/auth/sign-in").permitAll()
.requestMatchers("/auth/sign-up").permitAll()
.anyRequest().hasAuthority("ROLE_access")
.and()
.httpBasic(Customizer.withDefaults())
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);通过以上配置,只有具有 "ROLE_access" 权限的令牌才能访问受保护的端点。由于刷新令牌不包含此权限,因此只能用于刷新令牌端点。
JWT 声明名称配置一致性
在配置 JWT 时,务必确保在整个应用程序中使用的声明名称保持一致。例如,如果在 WebSecurityConfig 类中将权限声明名称设置为 "roles":
jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("roles");那么在 JwtTokenServiceImpl 类中生成 JWT 时,也应该使用 "roles" 作为声明名称:
JwtClaimsSet claims = JwtClaimsSet.builder()
.issuer("self")
.issuedAt(now)
.expiresAt(now.plus(2, ChronoUnit.MINUTES))
.subject(user.getUsername())
.claim("roles", accessScope)
.build();如果在不同的地方使用了不同的声明名称(例如 "scope" 和 "roles"),Spring Security 将无法正确解析令牌中的权限信息,导致身份验证和授权失败。
总结
通过为访问令牌添加特定权限并配置 Spring Security,可以有效地限制刷新令牌的使用范围,从而提高系统的安全性。同时,务必确保在整个应用程序中使用的 JWT 声明名称保持一致,以避免身份验证和授权问题。虽然本文没有涉及刷新令牌的单次使用,但是可以考虑将刷新令牌存储在数据库中,并在每次使用后将其删除,以实现单次使用的功能。这需要额外的数据库操作和管理,但可以进一步提高安全性。










