Now JwtGrantedAuthoritiesConverter only support one claim (scp/scope -> SCOPE_), now we have request to support multiple claims. For example:

scp -> SCOPE_
roles -> ROLE_

So I suggest to implement JwtGrantedAuthoritiesConverter like this:

public class JwtGrantedAuthoritiesConverter implements Converter<Jwt, Collection<GrantedAuthority>> {

    private final Log logger = LogFactory.getLog(getClass());
    private final Map<String, String> claimToAuthorityPrefixMap;

    public JwtGrantedAuthoritiesConverter(Map<String, String> claimToAuthorityPrefixMap) {
        this.claimToAuthorityPrefixMap = Collections.unmodifiableMap(claimToAuthorityPrefixMap);
    }

    @Override
    public Collection<GrantedAuthority> convert(Jwt jwt) {
        return getAuthorityStrings(jwt, this.claimToAuthorityPrefixMap);
    }

    private Collection<GrantedAuthority> getAuthorityStrings(Jwt jwt, Map<String, String> claimToAuthorityPrefixMap) {
        Collection<String> authorityStrings = new HashSet<>();
        for (String claim : claimToAuthorityPrefixMap.keySet()) {
            String authorityPrefix = claimToAuthorityPrefixMap.get(claim);
            getClaimValues(jwt, claim).stream()
                                      .map(claimValue -> authorityPrefix + claimValue)
                                      .forEach(authorityStrings::add);
        }
        return authorityStrings.stream()
                               .map(SimpleGrantedAuthority::new)
                               .collect(Collectors.toSet());
    }

    private Collection<String> getClaimValues(Jwt jwt, String claimName) {
        if (claimName == null) {
            this.logger.trace("Returning no authorities since could not find any claims that might contain scopes");
            return Collections.emptyList();
        }
        if (this.logger.isTraceEnabled()) {
            this.logger.trace(LogMessage.format("Looking for scopes in claim %s", claimName));
        }
        Object claimValue = jwt.getClaim(claimName);
        if (claimValue instanceof String) {
            if (StringUtils.hasText((String) claimValue)) {
                return Arrays.asList(((String) claimValue).split(" "));
            }
            return Collections.emptyList();
        }
        if (claimValue instanceof Collection) {
            return castToCollection(claimValue);
        }
        return Collections.emptyList();
    }

    @SuppressWarnings("unchecked")
    private Collection<String> castToCollection(Object object) {
        return (Collection<String>) object;
    }
}

And use it like this:

public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http.authorizeRequests()
                .anyRequest().authenticated()
                .and()
            .oauth2ResourceServer()
                .jwt()
                    .jwtAuthenticationConverter(jwtAuthenticationConverter())
                    .and()
                .and();
        // @formatter:on
    }

    private JwtAuthenticationConverter jwtAuthenticationConverter() {
        JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
        converter.setJwtGrantedAuthoritiesConverter(new JwtGrantedAuthoritiesConverter(claimToAuthorityPrefixMap()));
        return converter;
    }

    private Map<String, String> claimToAuthorityPrefixMap() {
        Map<String, String> claimToAuthorityPrefixMap = new HashMap<>();
        claimToAuthorityPrefixMap.put("scope", "SCOPE_");
        claimToAuthorityPrefixMap.put("scp", "SCOPE_");
        claimToAuthorityPrefixMap.put("roles", "ROLE_");
        return claimToAuthorityPrefixMap;
    }
}

Comment From: jzheaux

This appears to duplicate #8844. Let's continue the conversation over there.

For a quick reference to your specific use case, though, you can do this using DelegatingJwtGrantedAuthoritiesConverter:

JwtGrantedAuthoritiesConverter authoritiesConverter() {
    JwtGrantedAuthoritiesConverter scp = new JwtGrantedAuthoritiesConverter();
    JwtGrantedAuthoritiesConverter roles = new JwtGrantedAuthoritiesConverter();
    roles.setAuthorityPrefix("ROLE_");
    roles.setAuthorityClaimName("roles");
    return new DelegatingJwtGrantedAuthoritiesConverter(scp, roles);
}

Comment From: chenrujun

@jzheaux Thank you for your response. I have another question: How about creating an constructor, so we can write code like this:

JwtGrantedAuthoritiesConverter authoritiesConverter() {
    JwtGrantedAuthoritiesConverter scp = new JwtGrantedAuthoritiesConverter();
    JwtGrantedAuthoritiesConverter roles = new JwtGrantedAuthoritiesConverter("roles", "ROLE_");
    return new DelegatingJwtGrantedAuthoritiesConverter(scp, roles);
}

Comment From: jzheaux

@chenrujun, thanks for the suggestion. Please read up on #8844 if you haven't already as there is a similar suggestion there. We can continue trading ideas over there if you like.