如何操作:在JWT访问Tokens中添加自定义声明权限

此指南演示了如何在JWT访问Tokens中添加资源拥有者权限。 术语“权限”可能表示资源拥有所具有的不同形式,例如角色、权限或资源拥有的组。spring-doc.cadn.net.cn

要使资源所有者的权限信息能够提供给资源服务器,我们需要在访问Tokens中添加自定义声明。 当客户端使用访问Tokens访问受保护的资源时,资源服务器将能够获取到有关资源所有者级别的访问以及其他潜在用途和好处的信息。spring-doc.cadn.net.cn

添加自定义声明到JWT访问Tokens

您可以使用OAuth2TokenCustomizer<JWTEncodingContext>@Bean向访问Tokens添加自定义声明。 请注意,这个@Bean只能被定义一次,因此在定制适当的Tokens类型时需格外小心——在这种情况下是访问Tokens。 如果您想自定义IDTokens,请参阅用户信息映射器指南以获取更多信息。spring-doc.cadn.net.cn

以下是一个向访问Tokens中添加自定义声明的示例——换句话说,授权服务器发放的所有访问Tokens都将包含这些自定义声明。spring-doc.cadn.net.cn

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访问Tokens中

要将资源所有者的权限添加到JWT访问Tokens中,我们可以参考上述自定义声明映射方法,并填充一个包含资源所有者权限的自定义声明,使用Principalspring-doc.cadn.net.cn

我们为了演示目的定义了一个示例用户,并为其设置了一系列权限。同时,我们在访问Tokens中填充了一个自定义声明,包含了这些权限。spring-doc.cadn.net.cn

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)
				});
			}
		};
	}
}
1 定义一个示例用户 user1,使用内存中的 UserDetailsService
2 user1分配角色。
3 定义一个OAuth2TokenCustomizer<JwtEncodingContext>@Bean,用于自定义JWT声明。
4 检查是否为访问Tokens。
5 通过JwtEncodingContext访问默认声明。
6 Principal对象中提取角色。角色信息存储为一个以ROLE_前缀的字符串,因此我们在这里移除这个前缀。
7 设置自定义声明roles为上一步收集的角色集合。

由于进行了此自定义设置,用户的相关信息将作为自定义声明包含在访问Tokens中。spring-doc.cadn.net.cn