我正在实现基于角色的Jwt,它在Jwt声明中包含authorities属性。目前,我使用Jwt定制器从上下文中提取身份验证对象,并将其放入Jwt声明中,如下所示。问题是,JwtEncodingContext上的权限不会更改,因为它仅在令牌发布时第一次存储。
@Bean
fun jwtCustomizer(): OAuth2TokenCustomizer<JwtEncodingContext> {
return OAuth2TokenCustomizer { context: JwtEncodingContext ->
val principal: Authentication = context.getPrincipal() // <-- this won't change
val user: UserDetailsImpl = principal.principal as UserDetailsImpl
context.claims.claim("userId", user.getUserId())
context.claims.claim("authorities", user.getAuthorities())
}
}
但是,用户的权限是可以定期更改的,比如用户的权限从“ADMIN”更改为“USER”,但是由于JwtEncodingContext不会更改,所以每次刷新token时,他仍然拥有“ADMIN”的权限,所以我不太清楚如何正确处理这个问题,我能想到的一个办法是通过撤销token来强制用户重新登录。但这种解决方案可能会给用户带来非常糟糕的体验,因为权限可能会在我的系统中定期更改。或者,可能有点肮脏的解决方案是从用户详细信息中查询数据,并将其放在像这样的声明中。
@Bean
fun jwtCustomizer(): OAuth2TokenCustomizer<JwtEncodingContext> {
return OAuth2TokenCustomizer { context: JwtEncodingContext ->
val principal: Authentication = context.getPrincipal() // <-- this won't change
val user: UserDetailsImpl = userDetailsRepository.findById(principal.getUserId())
context.claims.claim("userId", user.getUserId())
context.claims.claim("authorities", user.getAuthorities())
}
}
你知道怎么处理吗?
1条答案
按热度按时间mlnl4t2r1#
您概述的解决方案是一个可能的选择,在我看来是一个良好的开端。在评论中讨论,我不同意这是一个“肮脏”的解决方案,因为您 * 正在 * 实际使用内置组件,即
OAuth2TokenCustomizer
和UserDetailsService
。Spring Security中的内置组件旨在允许您将授权规则和需求集成到框架中。这是你正在尝试做的。如果你有一个可行的解决方案来做这件事,我会说你有一些东西可以建立,你可以随时改进它以后或试验其他方法,如果需要的话。另一个选项是仅包括
roles
声明(例如"roles": ["ROLE_ADMIN"]
),并在资源服务器中执行权限Map。这样做的好处是始终保持最新,但缺点是需要许多资源服务器查询存储角色到权限Map的数据库,因此无法扩展。如果您对此感兴趣,您将在资源服务器端使用来自spring-security-oauth2-resource-server
的JwtGrantedAuthoritiesMapper
。如果需要立即撤销,我也推荐使用opaque令牌而不是JWT,如果使用opaque令牌也有类似的支持,尽管在这种情况下最好在authz服务器上定制声明。