Spring Security Spring Auth Server JwtGenerator将LinkedHashMap类型的token setting settings.token.access-token-format转换为OAuth2 TokenFormat

o0lyfsai  于 2023-08-05  发布在  Spring
关注(0)|答案(1)|浏览(102)

第一个月
spring-security-oauth2-authorization-server 1.1.1

java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat is in unnamed module of loader 'app')
    at org.springframework.security.oauth2.server.authorization.settings.TokenSettings.getAccessTokenFormat(TokenSettings.java:66) ~[spring-security-oauth2-authorization-server-1.1.1.jar:1.1.1]
    at org.springframework.security.oauth2.server.authorization.token.JwtGenerator.generate(JwtGenerator.java:83) ~[spring-security-oauth2-authorization-server-1.1.1.jar:1.1.1]
    at org.springframework.security.oauth2.server.authorization.token.JwtGenerator.generate(JwtGenerator.java:60) ~[spring-security-oauth2-authorization-server-1.1.1.jar:1.1.1]
    at org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientCredentialsAuthenticationProvider.authenticate(OAuth2ClientCredentialsAuthenticationProvider.java:125) ~[spring-security-oauth2-authorization-server-1.1.1.jar:1.1.1]

字符串
不知道我是否排除了一些时髦的新功能...?我从来不知道这是一个功能,所以请纠正我。
Class OAuth2TokenFormat

OAuth2TokenFormat(String value)


x1c 0d1x的数据
RegisteredClient使用文档中的JPA示例创建。
认证服务器JPA示例

private RegisteredClient toRegisteredClient(RegisteredClientEntity registeredClientEntity) {
        
        Set<String> clientAuthenticationMethods = StringUtils.commaDelimitedListToSet(
            registeredClientEntity.getClientAuthenticationMethods());
        Set<String> authorizationGrantTypes = StringUtils.commaDelimitedListToSet(
            registeredClientEntity.getAuthorizationGrantTypes());
        Set<String> redirectUris = StringUtils.commaDelimitedListToSet(
            registeredClientEntity.getRedirectUris());
        Set<String> postLogoutRedirectUris = StringUtils.commaDelimitedListToSet(
            registeredClientEntity.getPostLogoutRedirectUris());
        Set<String> clientScopes = StringUtils.commaDelimitedListToSet(
            registeredClientEntity.getScopes());
        
        RegisteredClient.Builder builder =
            RegisteredClient
                .withId(registeredClientEntity.getId())
                .clientId(registeredClientEntity.getClientId())
                .clientIdIssuedAt(registeredClientEntity.getClientIdIssuedAt())
                .clientSecret(registeredClientEntity.getClientSecret())
                .clientSecretExpiresAt(registeredClientEntity.getClientSecretExpiresAt())
                .clientName(registeredClientEntity.getClientName())
                .clientAuthenticationMethods(
                    authenticationMethods ->
                        clientAuthenticationMethods
                            .forEach(authenticationMethod ->
                                authenticationMethods.add(resolveClientAuthenticationMethod(authenticationMethod))))
                .authorizationGrantTypes(grantTypes ->
                    authorizationGrantTypes
                        .forEach(grantType -> grantTypes.add(resolveAuthorizationGrantType(grantType))))
                .redirectUris(uris -> uris.addAll(redirectUris))
                .postLogoutRedirectUris(uris -> uris.addAll(postLogoutRedirectUris))
                .scopes(scopes -> scopes.addAll(clientScopes));
        
        Map<String, Object> clientSettingsMap = 
            MappingUtils.jsonStringToMap(objectMapper, registeredClientEntity.getClientSettings());
        
        builder.clientSettings(ClientSettings.withSettings(clientSettingsMap).build());
        
        Map<String, Object> tokenSettingsMap =
            MappingUtils.jsonStringToMap(objectMapper, registeredClientEntity.getTokenSettings());
        
        builder.tokenSettings(TokenSettings.withSettings(tokenSettingsMap).build());
        
        return builder.build();
    }


一个测试来证明这一点以及输出:

package co.mytest.authserver;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.SneakyThrows;
import org.junit.jupiter.api.Test;
import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat;
import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;

import java.util.Map;

public class TokenSettingsTest {
    
    @SneakyThrows
    @Test
    void test(){
    
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule());
        
        TokenSettings tokenSettings = TokenSettings.builder().build();
        String tokenSettingsJson = objectMapper.writeValueAsString(tokenSettings.getSettings());
        
        System.out.println(tokenSettings);
        
        Map<String, Object> tokenSettingsMap =
            objectMapper.readValue(
                tokenSettingsJson, new TypeReference<Map<String, Object>>(){});
    
        TokenSettings deserializedTokenSettings = TokenSettings.withSettings(tokenSettingsMap).build();
        OAuth2TokenFormat oAuth2TokenFormat = deserializedTokenSettings.getAccessTokenFormat();
        System.out.println("TokenSettings created");
    }
    
    //AbstractSettings {settings={settings.token.reuse-refresh-tokens=true, settings.token.id-token-signature-algorithm=RS256, settings.token.access-token-time-to-live=PT5M, settings.token.access-token-format=org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat@face4f32, settings.token.refresh-token-time-to-live=PT1H, settings.token.authorization-code-time-to-live=PT5M, settings.token.device-code-time-to-live=PT5M}}
    //
    //java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat is in unnamed module of loader 'app')
    //
    //  at org.springframework.security.oauth2.server.authorization.settings.TokenSettings.getAccessTokenFormat(TokenSettings.java:66)
    
}


感谢@SteveRiesenberg!这会让很多人怀疑
我最初的怀疑得到了证实--你需要召唤一些时髦的功能。
ObjectMapper需要准备:

ClassLoader classLoader = AuthServerApplication.class.getClassLoader();
        List<Module> securityModules = SecurityJackson2Modules.getModules(classLoader);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModules(securityModules);
        objectMapper.registerModule(new OAuth2AuthorizationServerJackson2Module());


创建Jackson定制器时请小心:

@Bean
    public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
        
        ClassLoader classLoader = ValiantAuthServerApplication.class.getClassLoader();
        List<Module> securityModules = SecurityJackson2Modules.getModules(classLoader);
        securityModules.add(new OAuth2AuthorizationServerJackson2Module());
    
        // The modules AbstractList passed to the consumer doesn't support add()??? Workaround. 
        return jacksonObjectMapperBuilder -> {
            jacksonObjectMapperBuilder.modulesToInstall(securityModules::addAll);
            jacksonObjectMapperBuilder.modulesToInstall(securityModules.toArray(new Module[0]));
        };
    }

jvlzgdj9

jvlzgdj91#

ObjectMapper需要特殊的准备。(见原题)
我在Jackson 2 ObjectMapperBuilderCustomizer中有一个错误,导致所需的模块无法加载。小心定制者/构建者。我遇到了一些意想不到的行为。

相关问题