操作指南:在 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)
				});
			}
		};
	}
}
1 定義一個帶有記憶體中的 UserDetailsService 的示例使用者 user1
2 user1 分配角色。
3 定義一個允許自定義 JWT 宣告的 OAuth2TokenCustomizer<JwtEncodingContext> @Bean
4 檢查 JWT 是否為訪問令牌。
5 透過 JwtEncodingContext 訪問預設宣告。
6 Principal 物件中提取角色。 角色資訊儲存為帶有 ROLE_ 字首的字串,因此我們在此處刪除字首。
7 將自定義宣告 roles 設定為從上一步收集的角色集。

作為此自定義的結果,有關使用者的許可權資訊將作為自定義宣告包含在訪問令牌中。