Spring Security Oauth2 返回非标准数据结构 OAuth2AccessToken 序列化问题

问题描述:

在Spring框架中,自定义配置了 FastJsonHttpMessageConverter ,覆盖掉 MappingJackson2HttpMessageConverter,导致返回时 序列化出现问题。

预期: 

{
    "access_token": "f7d77b3f-61f1-4c1e-975e-c6b3bb5f244d",
    "token_type": "bearer",
    "refresh_token": "35cca126-928a-4429-8bd7-86afb0250559",
    "expires_in": 3599,
    "scope": "mgtapi_admininfo"
}

实际返回结果:

{
    "additionalInformation": {},
    "expiration": "2019-03-06 15:49:06",
    "expired": false,
    "expiresIn": 2141,
    "refreshToken": {
        "expiration": "2019-03-06 16:49:06",
        "value": "35cca126-928a-4429-8bd7-86afb0250559"
    },
    "scope": [
        "mgtapi_admininfo"
    ],
    "tokenType": "bearer",
    "value": "f7d77b3f-61f1-4c1e-975e-c6b3bb5f244d"
}

问题定位:

因为在WebMvcConfigurer中自定义配置了消息处理,覆盖了默认的消息处理器

public class BaseWebMvcConfig implements WebMvcConfigurer {

    @Bean
    public FastJsonHttpMessageConverter fastJsonHttpMessageConverter() {
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        SerializeConfig config = new SerializeConfig();
        config.put(Date.class, new SimpleDateFormatSerializer("yyyy-MM-dd HH:mm:ss"));
        fastJsonConfig.setSerializeConfig(config);

        fastConverter.setFastJsonConfig(fastJsonConfig);
        return fastConverter;
    }

    @Override
    public void configureMessageConverters(List> converters) {
        converters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
        converters.add(fastJsonHttpMessageConverter());
    }
}

读过源码后发现 configureMessageConverters 配置,如果有配置,就会使用用户配置的两种消息处理器,如果没有配置,则会默认添加8个消息处理器。

WebMvcConfigurationSupport.java

	protected final List> getMessageConverters() {
		if (this.messageConverters == null) {
			this.messageConverters = new ArrayList<>();
			configureMessageConverters(this.messageConverters);
			if (this.messageConverters.isEmpty()) {
				addDefaultHttpMessageConverters(this.messageConverters);
			}
			extendMessageConverters(this.messageConverters);
		}
		return this.messageConverters;
	}

然而OauthAccessToken 中注解以及内置实现的序列化只支持四种。OAuth2AccessTokenJackson2Serializer 和 OAuth2AccessTokenJackson2Deserializer

@org.codehaus.jackson.map.annotate.JsonSerialize(using = OAuth2AccessTokenJackson1Serializer.class)
@org.codehaus.jackson.map.annotate.JsonDeserialize(using = OAuth2AccessTokenJackson1Deserializer.class)
@com.fasterxml.jackson.databind.annotation.JsonSerialize(using = OAuth2AccessTokenJackson2Serializer.class)
@com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = OAuth2AccessTokenJackson2Deserializer.class)

public interface OAuth2AccessToken {

 

问题定位后,就可以着手解决了。方案有很多,我想到了两种。

第一种:

重新一个fastjson的序列化过滤器,针对某一个类做特殊处理。

参考资料:https://github.com/alibaba/fastjson/issues/1640

 

第二种:

自定义一个消息转换器,并让MappingJackson 消息转换器来处理Oauth2AccessToken的类返回信息。

    @Override
    public void extendMessageConverters(List> converters) {
        Oauth2HttpMessageConverter oauth2HttpMessageConverter = new Oauth2HttpMessageConverter();
        converters.add(0, oauth2HttpMessageConverter);
    }

Oauth2HttpMessageConverter 类

public class Oauth2HttpMessageConverter extends AbstractHttpMessageConverter {

    private final MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();

    public Oauth2HttpMessageConverter() {
        super(MediaType.APPLICATION_JSON_UTF8);
    }

    @Override
    protected boolean supports(Class clazz) {
        return clazz.equals(DefaultOAuth2AccessToken.class);
    }

    @Override
    protected DefaultOAuth2AccessToken readInternal(Class clazz, HttpInputMessage inputMessage)
            throws IOException, HttpMessageNotReadableException {
        throw new UnsupportedOperationException(
                "This converter is only used for converting DefaultOAuth2AccessToken to json.");
    }

    @Override
    protected void writeInternal(DefaultOAuth2AccessToken accessToken, HttpOutputMessage outputMessage) throws IOException,
            HttpMessageNotWritableException {
        mappingJackson2HttpMessageConverter.write(accessToken, MediaType.APPLICATION_JSON_UTF8, outputMessage);
    }
}

这样的话,Oauth的消息返回时,会被正确处理,就能得到自己想要的结果了。

你可能感兴趣的:(Spring)