瀏覽代碼

Add setter for authorities claim name in JwtGrantedAuthoritiesConverter

Prior to this change authorities are always mapped using well known
claim names ('scope' or 'scp'). To change this default behaviour the
converter had to be replaced completely with a custom one.
This commit adds an additional setter to configure a custom
claim name like e.g. 'roles'. Without specifying a custom claim name
the default claims to be used still remains to the well known ones.
This way the authorities can be mapped according to customized
token claims.

Fixes gh-7100
Andreas Falk 6 年之前
父節點
當前提交
0a058c973a

+ 19 - 0
oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtGrantedAuthoritiesConverter.java

@@ -43,6 +43,8 @@ public final class JwtGrantedAuthoritiesConverter implements Converter<Jwt, Coll
 
 
 	private String authorityPrefix = DEFAULT_AUTHORITY_PREFIX;
 	private String authorityPrefix = DEFAULT_AUTHORITY_PREFIX;
 
 
+	private String authoritiesClaimName;
+
 	/**
 	/**
 	 * Extract {@link GrantedAuthority}s from the given {@link Jwt}.
 	 * Extract {@link GrantedAuthority}s from the given {@link Jwt}.
 	 *
 	 *
@@ -70,7 +72,24 @@ public final class JwtGrantedAuthoritiesConverter implements Converter<Jwt, Coll
 		this.authorityPrefix = authorityPrefix;
 		this.authorityPrefix = authorityPrefix;
 	}
 	}
 
 
+	/**
+	 * Sets the name of token claim to use for mapping {@link GrantedAuthority authorities} by this converter.
+	 * Defaults to {@link JwtGrantedAuthoritiesConverter#WELL_KNOWN_AUTHORITIES_CLAIM_NAMES}.
+	 *
+	 * @param authoritiesClaimName The token claim name to map authorities
+	 * @since 5.2
+	 */
+	public void setAuthoritiesClaimName(String authoritiesClaimName) {
+		Assert.hasText(authoritiesClaimName, "authoritiesClaimName cannot be empty");
+		this.authoritiesClaimName = authoritiesClaimName;
+	}
+
 	private String getAuthoritiesClaimName(Jwt jwt) {
 	private String getAuthoritiesClaimName(Jwt jwt) {
+
+		if (this.authoritiesClaimName != null) {
+			return this.authoritiesClaimName;
+		}
+
 		for (String claimName : WELL_KNOWN_AUTHORITIES_CLAIM_NAMES) {
 		for (String claimName : WELL_KNOWN_AUTHORITIES_CLAIM_NAMES) {
 			if (jwt.containsClaim(claimName)) {
 			if (jwt.containsClaim(claimName)) {
 				return claimName;
 				return claimName;

+ 43 - 0
oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtGrantedAuthoritiesConverterTests.java

@@ -139,6 +139,49 @@ public class JwtGrantedAuthoritiesConverterTests {
 		assertThat(authorities).isEmpty();
 		assertThat(authorities).isEmpty();
 	}
 	}
 
 
+	@Test
+	public void convertWhenTokenHasCustomClaimNameThenCustomClaimNameAttributeIsTranslatedToAuthorities() {
+		Map<String, Object> claims = new HashMap<>();
+		claims.put("roles", Arrays.asList("message:read", "message:write"));
+		claims.put("scope", "missive:read missive:write");
+		Jwt jwt = this.jwt(claims);
+
+		JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
+		jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("roles");
+		Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
+
+		assertThat(authorities).containsExactly(
+				new SimpleGrantedAuthority("SCOPE_message:read"),
+				new SimpleGrantedAuthority("SCOPE_message:write"));
+	}
+
+	@Test
+	public void convertWhenTokenHasEmptyCustomClaimNameThenCustomClaimNameAttributeIsTranslatedToNoAuthorities() {
+		Map<String, Object> claims = new HashMap<>();
+		claims.put("roles", Collections.emptyList());
+		claims.put("scope", "missive:read missive:write");
+		Jwt jwt = this.jwt(claims);
+
+		JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
+		jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("roles");
+		Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
+
+		assertThat(authorities).isEmpty();
+	}
+
+	@Test
+	public void convertWhenTokenHasNoCustomClaimNameThenCustomClaimNameAttributeIsTranslatedToNoAuthorities() {
+		Map<String, Object> claims = new HashMap<>();
+		claims.put("scope", "missive:read missive:write");
+		Jwt jwt = this.jwt(claims);
+
+		JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
+		jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("roles");
+		Collection<GrantedAuthority> authorities = jwtGrantedAuthoritiesConverter.convert(jwt);
+
+		assertThat(authorities).isEmpty();
+	}
+
 	private Jwt jwt(Map<String, Object> claims) {
 	private Jwt jwt(Map<String, Object> claims) {
 		Map<String, Object> headers = new HashMap<>();
 		Map<String, Object> headers = new HashMap<>();
 		headers.put("alg", JwsAlgorithms.RS256);
 		headers.put("alg", JwsAlgorithms.RS256);