我现在通过尝试从 Keycloak 迁移到 Spring Authorization Server 来反对 JSON 反序列化一段时间(我仍然想知道所有这些问题是否是一个好主意)。无论如何...
首先尝试使用代码授权类型获取访问令牌,我在使用 CustomUserDetails 时遇到了异常
Caused by: java.lang.IllegalArgumentException: The class with com.company.user.CustomUserDetails and name of com.company.user.CustomUserDetails is not in the allowlist. If you believe this class is safe to deserialize, please provide an explicit mapping using Jackson annotations or by providing a Mixin. If the serialization is only done by a trusted source, you can also enable default typing. See https://github.com/spring-projects/spring-security/issues/4370 for details
我访问了链接https://github.com/spring-projects/spring-security/issues/4370但没有什么真正有用的。
根据错误信息我定义了这个CustomUserDetailsMixin
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
@JsonDeserialize(using = CustomUserDetailsSerializer.class)
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE,
isGetterVisibility = JsonAutoDetect.Visibility.NONE)
@JsonIgnoreProperties(ignoreUnknown = true)
public abstract class CustomUserDetailsMixin {
}
和
CustomUserDetailsSerializer
:
public class CustomUserDetailsSerializer extends JsonDeserializer<CustomUserDetails> {
private static final TypeReference<Set<SimpleGrantedAuthority>> SIMPLE_GRANTED_AUTHORITY_SET = new TypeReference<>() {
};
@Override
public CustomUserDetails deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
ObjectMapper mapper = (ObjectMapper) jp.getCodec();
JsonNode jsonNode = mapper.readTree(jp);
//there is an issue here :
Set<? extends GrantedAuthority> authorities = mapper.convertValue(jsonNode.get("authorities"), SIMPLE_GRANTED_AUTHORITY_SET);
}
}
并在这里注册:
@Configuration(proxyBeanMethods = false)
public class AuthorizationServerConfiguration {
@Bean
public OAuth2AuthorizationService oAuth2AuthorizationService(JdbcTemplate jdbcTemplate, RegisteredClientRepository registeredClientRepository) {
JdbcOAuth2AuthorizationService oAuth2AuthorizationService = new JdbcOAuth2AuthorizationService(jdbcTemplate, registeredClientRepository);
JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper rowMapper = new JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper(registeredClientRepository);
ClassLoader classLoader = JdbcOAuth2AuthorizationService.class.getClassLoader();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModules(new CoreJackson2Module());
objectMapper.registerModules(SecurityJackson2Modules.getModules(classLoader));
objectMapper.registerModule(new OAuth2AuthorizationServerJackson2Module());
//registering the mixin
objectMapper.addMixIn(CustomUserDetails.class, CustomUserDetailsMixin.class);
rowMapper.setObjectMapper(objectMapper);
oAuth2AuthorizationService.setAuthorizationRowMapper(rowMapper);
return oAuth2AuthorizationService;
}
}
但是现在我有另一个错误:
java.lang.IllegalArgumentException: Could not resolve type id 'java.util.ImmutableCollections$ListN' as a subtype of `java.util.Set<org.springframework.security.core.authority.SimpleGrantedAuthority>`: Not a subtype
at [Source: UNKNOWN; byte offset: #UNKNOWN]
at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService$OAuth2AuthorizationRowMapper.parseMap(JdbcOAuth2AuthorizationService.java:467)
看了一下spring security保存在db中的json,是这样的:
{
"@class": "java.util.Collections$UnmodifiableMap",
"java.security.Principal": {
"@class": "org.springframework.security.authentication.UsernamePasswordAuthenticationToken",
"authorities": [
"java.util.Collections$UnmodifiableRandomAccessList",
[
{
"@class": "org.springframework.security.core.authority.SimpleGrantedAuthority",
"authority": "ROLE_USER"
}
]
],
}
....
}
问题是如何解决最后一个错误?
json 中的“java.util.Collections$UnmodifiableRandomAccessList”类型信息与您的不兼容 SIMPLE_GRANTED_AUTHORITY_SET 类型引用,所以有一个简单的方法来处理。
使用CoreJackson2Module中已经注册的类型引用,然后将其转换为实际需要的类型。
TypeReference<List<SimpleGrantedAuthority>> listType = new TypeReference<>() {
};
List<SimpleGrantedAuthority> authoritiesList = mapper.convertValue(jsonNode.get("authorities"), listType);
Set<? extends SimpleGrantedAuthority> authorities = authoritiesList.stream().collect(Collectors.toSet());