如何:在 JWT 访问令牌中添加权限作为自定义声明
本指南演示了如何将资源所有者权限添加到 JWT 访问令牌中。术语“权限”可以代表资源所有者的不同形式,例如角色、权限或组。
为了让资源服务器能够获取资源所有者的权限信息,我们在访问令牌中添加了自定义声明。当客户端使用访问令牌访问受保护资源时,资源服务器将能够获取资源所有者的访问级别信息,以及其他潜在用途和优势。
向 JWT 访问令牌添加自定义声明
您可以通过定义一个 OAuth2TokenCustomizer<JWTEncodingContext> 类型的 @Bean 来向访问令牌添加自定义声明。请注意,此 @Bean 只能定义一次,因此必须确保您正在定制适当的令牌类型——在本例中为访问令牌。如果您有兴趣定制 ID 令牌,请参阅用户信息映射器指南获取更多信息。
以下是一个向访问令牌添加自定义声明的示例——也就是说,授权服务器颁发的每个访问令牌都将包含这些自定义声明。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer;
@Configuration
public class CustomClaimsConfiguration {
@Bean
public OAuth2TokenCustomizer<JwtEncodingContext> jwtTokenCustomizer() {
return (context) -> {
if (OAuth2TokenType.ACCESS_TOKEN.equals(context.getTokenType())) {
context.getClaims().claims((claims) -> {
claims.put("claim-1", "value-1");
claims.put("claim-2", "value-2");
});
}
};
}
}
将权限作为自定义声明添加到 JWT 访问令牌
要将资源所有者的权限添加到 JWT 访问令牌中,我们可以参考上述自定义声明映射方法,并将 Principal 的权限填充到自定义声明中。
我们定义了一个示例用户,并为其分配了一组权限用于演示目的,然后将这些权限作为自定义声明填充到访问令牌中。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
@Configuration
public class CustomClaimsWithAuthoritiesConfiguration {
@Bean
public UserDetailsService users() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("user1") 1
.password("password")
.roles("user", "admin") 2
.build();
return new InMemoryUserDetailsManager(user);
}
@Bean
public OAuth2TokenCustomizer<JwtEncodingContext> jwtTokenCustomizer() { 3
return (context) -> {
if (OAuth2TokenType.ACCESS_TOKEN.equals(context.getTokenType())) { 4
context.getClaims().claims((claims) -> { 5
Set<String> roles = AuthorityUtils.authorityListToSet(context.getPrincipal().getAuthorities())
.stream()
.map(c -> c.replaceFirst("^ROLE_", ""))
.collect(Collectors.collectingAndThen(Collectors.toSet(), Collections::unmodifiableSet)); 6
claims.put("roles", roles); 7
});
}
};
}
}
定义一个示例用户
user1,使用内存中的UserDetailsService。为
user1分配角色。定义一个
OAuth2TokenCustomizer<JwtEncodingContext>@Bean,用于自定义 JWT 声明。检查 JWT 是否为访问令牌。
通过
JwtEncodingContext访问默认声明。从
Principal对象中提取角色。角色信息以ROLE_为前缀存储为字符串,因此我们在此处去除前缀。将自定义声明
roles设置为从上一步收集到的角色集合。
由于此定制,用户的权限信息将作为自定义声明包含在访问令牌中。