spring-security自定义User抛出java.lang.IllegalArgumentException异常

spring-security自定义User抛出java.lang.IllegalArgumentException异常

具体异常

	java.lang.IllegalArgumentException: The class with com.xxxx.CustomUser and name of com.xxxx.CustomUser 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
	at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService$OAuth2AuthorizationRowMapper.parseMap(JdbcOAuth2AuthorizationService.java:462) ~[spring-security-oauth2-authorization-server-0.3.0.jar:0.3.0]
	at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService$OAuth2AuthorizationRowMapper.mapRow(JdbcOAuth2AuthorizationService.java:347) ~[spring-security-oauth2-authorization-server-0.3.0.jar:0.3.0]
	at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService$OAuth2AuthorizationRowMapper.mapRow(JdbcOAuth2AuthorizationService.java:318) ~[spring-security-oauth2-authorization-server-0.3.0.jar:0.3.0]
	at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:94) ~[spring-jdbc-5.3.15.jar:5.3.15]
	at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:61) ~[spring-jdbc-5.3.15.jar:5.3.15]
	at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:723) ~[spring-jdbc-5.3.15.jar:5.3.15]
	at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:651) ~[spring-jdbc-5.3.15.jar:5.3.15]
	at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:713) ~[spring-jdbc-5.3.15.jar:5.3.15]
	at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:744) ~[spring-jdbc-5.3.15.jar:5.3.15]
	at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:799) ~[spring-jdbc-5.3.15.jar:5.3.15]
	at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService.findBy(JdbcOAuth2AuthorizationService.java:266) ~[spring-security-oauth2-authorization-server-0.3.0.jar:0.3.0]
	at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService.findByToken(JdbcOAuth2AuthorizationService.java:251) ~[spring-security-oauth2-authorization-server-0.3.0.jar:0.3.0]
	at org.springframework.security.oauth2.server.authorization.authentication.CodeVerifierAuthenticator.authenticate(CodeVerifierAuthenticator.java:77) ~[spring-security-oauth2-authorization-server-0.3.0.jar:0.3.0]
	at org.springframework.security.oauth2.server.authorization.authentication.CodeVerifierAuthenticator.authenticateIfAvailable(CodeVerifierAuthenticator.java:66) ~[spring-security-oauth2-authorization-server-0.3.0.jar:0.3.0]
	at org.springframework.security.oauth2.server.authorization.authentication.ClientSecretAuthenticationProvider.authenticate(ClientSecretAuthenticationProvider.java:111) ~[spring-security-oauth2-authorization-server-0.3.0.jar:0.3.0]
	at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:182) ~[spring-security-core-5.6.1.jar:5.6.1]
	at org.springframework.security.oauth2.server.authorization.web.OAuth2ClientAuthenticationFilter.doFilterInternal(OAuth2ClientAuthenticationFilter.java:120) ~[spring-security-oauth2-authorization-server-0.3.0.jar:0.3.0]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.15.jar:5.3.15]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationServerMetadataEndpointFilter.doFilterInternal(OAuth2AuthorizationServerMetadataEndpointFilter.java:77) ~[spring-security-oauth2-authorization-server-0.3.0.jar:0.3.0]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.15.jar:5.3.15]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.oauth2.server.authorization.web.NimbusJwkSetEndpointFilter.doFilterInternal(NimbusJwkSetEndpointFilter.java:85) ~[spring-security-oauth2-authorization-server-0.3.0.jar:0.3.0]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.15.jar:5.3.15]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.oauth2.server.authorization.oidc.web.OidcProviderConfigurationEndpointFilter.doFilterInternal(OidcProviderConfigurationEndpointFilter.java:79) ~[spring-security-oauth2-authorization-server-0.3.0.jar:0.3.0]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.15.jar:5.3.15]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationEndpointFilter.doFilterInternal(OAuth2AuthorizationEndpointFilter.java:140) ~[spring-security-oauth2-authorization-server-0.3.0.jar:0.3.0]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.15.jar:5.3.15]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103) ~[spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89) ~[spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:117) ~[spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.15.jar:5.3.15]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) ~[spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) ~[spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.15.jar:5.3.15]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.oauth2.server.authorization.web.ProviderContextFilter.doFilterInternal(ProviderContextFilter.java:63) ~[spring-security-oauth2-authorization-server-0.3.0.jar:0.3.0]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.15.jar:5.3.15]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110) ~[spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80) ~[spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55) ~[spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.15.jar:5.3.15]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211) ~[spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183) ~[spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.debug.DebugFilter.invokeWithWrappedRequest(DebugFilter.java:90) ~[spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.debug.DebugFilter.doFilter(DebugFilter.java:78) ~[spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.security.web.debug.DebugFilter.doFilter(DebugFilter.java:67) ~[spring-security-web-5.6.1.jar:5.6.1]
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354) ~[spring-web-5.3.15.jar:5.3.15]
	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) ~[spring-web-5.3.15.jar:5.3.15]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.56.jar:9.0.56]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.56.jar:9.0.56]
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.15.jar:5.3.15]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.15.jar:5.3.15]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.56.jar:9.0.56]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.56.jar:9.0.56]
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.15.jar:5.3.15]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.15.jar:5.3.15]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.56.jar:9.0.56]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.56.jar:9.0.56]
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.15.jar:5.3.15]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.15.jar:5.3.15]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.56.jar:9.0.56]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.56.jar:9.0.56]
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) ~[tomcat-embed-core-9.0.56.jar:9.0.56]
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.56.jar:9.0.56]
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540) ~[tomcat-embed-core-9.0.56.jar:9.0.56]
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) ~[tomcat-embed-core-9.0.56.jar:9.0.56]
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.56.jar:9.0.56]
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.56.jar:9.0.56]
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) ~[tomcat-embed-core-9.0.56.jar:9.0.56]
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382) ~[tomcat-embed-core-9.0.56.jar:9.0.56]
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.56.jar:9.0.56]
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895) ~[tomcat-embed-core-9.0.56.jar:9.0.56]
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732) ~[tomcat-embed-core-9.0.56.jar:9.0.56]
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.56.jar:9.0.56]
	at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.56.jar:9.0.56]
	at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.56.jar:9.0.56]
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.56.jar:9.0.56]
	at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]

抛出异常的原因

背景是我使用了Spring Authorization Server 0.3.0的OAuth2的authorization_code授权类型,需要对资源所有者进行身份验证。但我对org.springframework.security.core.userdetails.User类进行扩展com.xxxx.CustomUser,导致在资源所有者登录成功后,在根据authorization_code获取token时的执行期间查询数据库表oauth2_authorization信息后再转化为具体对象抛出异常。
具体查看异常位置,在JdbcOAuth2AuthorizationService的内部类OAuth2AuthorizationRowMapper的mapRow方法中

public OAuth2Authorization mapRow(ResultSet rs, int rowNum) throws SQLException {
	// ......
	Map<String, Object> attributes = parseMap(getLobValue(rs, "attributes"));
	// ......
}

分析发现getLobValue(rs, “attributes”)方法获取的是对应表oauth2_authorization的attributes字段,oauth2_authorization表结构如下:

CREATE TABLE `oauth2_authorization` (
  `id` varchar(100) NOT NULL,
  `registered_client_id` varchar(100) NOT NULL,
  `principal_name` varchar(200) NOT NULL,
  `authorization_grant_type` varchar(100) NOT NULL,
  `attributes` blob,
  `state` varchar(500) DEFAULT NULL,
  `authorization_code_value` blob,
  `authorization_code_issued_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `authorization_code_expires_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `authorization_code_metadata` blob,
  `access_token_value` blob,
  `access_token_issued_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `access_token_expires_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `access_token_metadata` blob,
  `access_token_type` varchar(100) DEFAULT NULL,
  `access_token_scopes` varchar(1000) DEFAULT NULL,
  `oidc_id_token_value` blob,
  `oidc_id_token_issued_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `oidc_id_token_expires_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `oidc_id_token_metadata` blob,
  `refresh_token_value` blob,
  `refresh_token_issued_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `refresh_token_expires_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `refresh_token_metadata` blob,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

attributes存储的是一个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_common"
				}
			]
		],
		"details": {
			"@class": "org.springframework.security.web.authentication.WebAuthenticationDetails",
			"remoteAddress": "127.0.0.1",
			"sessionId": "C79A07F205A263A7423C8645D6A37BBC"
		},
		"authenticated": true,
		"principal": {
			"@class": "com.xxxx.CustomUser",
			"password": null,
			"username": "admin",
			"authorities": [
				"java.util.Collections$UnmodifiableSet",
				[
					{
						"@class": "org.springframework.security.core.authority.SimpleGrantedAuthority",
						"authority": "ROLE_common"
					}
				]
			],
			"accountNonExpired": true,
			"accountNonLocked": true,
			"credentialsNonExpired": true,
			"enabled": true,
			"permissions": [
				"java.util.ArrayList",
				[
					{
						"@class": "com.bulv.security.authorization.config.login.PermissionGrantedAuthority",
						"targetDomain": "system/user/index",
						"authority": "system:user:list"
					}
				]
			]
		},
		"credentials": null
	},
	"org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest": {
		"@class": "org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest",
		"authorizationUri": "http://127.0.0.1:9200/oauth2/authorize",
		"authorizationGrantType": {
			"value": "authorization_code"
		},
		"responseType": {
			"value": "code"
		},
		"clientId": "bulv-app",
		"redirectUri": "http://127.0.0.1/oauth2/code",
		"scopes": [
			"java.util.Collections$UnmodifiableSet",
			[
				"user_info",
				"openid",
				"client.create"
			]
		],
		"state": "wWxnPj3KQeJYjFZIWZ1e_KvHpZOvlyp8DK9tQczrg6E=",
		"additionalParameters": {
			"@class": "java.util.Collections$UnmodifiableMap",
			"nonce": "-CyFrwZsxGOzu67cdN80FV1V893gRcprFy7DKDfTkg4"
		},
		"authorizationRequestUri": "http://127.0.0.1:9200/oauth2/authorize?response_type=code&client_id=bulv-app&scope=user_info%20openid%20client.create&state=wWxnPj3KQeJYjFZIWZ1e_KvHpZOvlyp8DK9tQczrg6E%3D&redirect_uri=http://127.0.0.1/oauth2/code&nonce=-CyFrwZsxGOzu67cdN80FV1V893gRcprFy7DKDfTkg4",
		"attributes": {
			"@class": "java.util.Collections$UnmodifiableMap"
		}
	},
	"org.springframework.security.oauth2.server.authorization.OAuth2Authorization.AUTHORIZED_SCOPE": [
		"java.util.Collections$UnmodifiableSet",
		[
			"user_info",
			"openid",
			"client.create"
		]
	]
}

异常翻译过来告诉我CustomUser类不在允许列表中。如果您认为此类可以安全地反序列化,请使用Jackson注释或提供 Mixin提供显式映射。如果序列化仅由受信任的来源完成,您还可以启用默认类型。详见 https://github.com/spring-projects/spring-security/issues/4370。说实话没看懂什么意思。但我大概明白和Jackson 有关系。后来在查看源码我发现在创建JdbcOAuth2AuthorizationService对象时属性authorizationParametersMapper实例化时,对authorizationParametersMapper的属性objectMapper默认设置了一些属性,而这些属性中正有被我覆盖的默认的org.springframework.security.core.userdetails.User类

public static class OAuth2AuthorizationParametersMapper implements Function<OAuth2Authorization, List<SqlParameterValue>> {
		private ObjectMapper objectMapper = new ObjectMapper();

		public OAuth2AuthorizationParametersMapper() {
			ClassLoader classLoader = JdbcOAuth2AuthorizationService.class.getClassLoader();
			List<Module> securityModules = SecurityJackson2Modules.getModules(classLoader);
			this.objectMapper.registerModules(securityModules);
			this.objectMapper.registerModule(new OAuth2AuthorizationServerJackson2Module());
		}
		
	// ...省略...
}

public final class SecurityJackson2Modules {
	// ...省略...
	
	/**
	 * @param loader the ClassLoader to use
	 * @return List of available security modules in classpath.
	 */
	public static List<Module> getModules(ClassLoader loader) {
		List<Module> modules = new ArrayList<>();
		for (String className : securityJackson2ModuleClasses) {
			addToModulesList(loader, modules, className);
		}
		if (ClassUtils.isPresent("javax.servlet.http.Cookie", loader)) {
			addToModulesList(loader, modules, webServletJackson2ModuleClass);
		}
		if (ClassUtils.isPresent("org.springframework.security.oauth2.client.OAuth2AuthorizedClient", loader)) {
			addToModulesList(loader, modules, oauth2ClientJackson2ModuleClass);
		}
		if (ClassUtils.isPresent(javaTimeJackson2ModuleClass, loader)) {
			addToModulesList(loader, modules, javaTimeJackson2ModuleClass);
		}
		return modules;
	}
	
	// ...省略...
}

public final class SecurityJackson2Modules {
	private static final Log logger = LogFactory.getLog(SecurityJackson2Modules.class);

	private static final List<String> securityJackson2ModuleClasses = Arrays.asList(
			"org.springframework.security.jackson2.CoreJackson2Module",
			"org.springframework.security.cas.jackson2.CasJackson2Module",
			"org.springframework.security.web.jackson2.WebJackson2Module",
			"org.springframework.security.web.server.jackson2.WebServerJackson2Module");

	private static final String webServletJackson2ModuleClass = "org.springframework.security.web.jackson2.WebServletJackson2Module";

	private static final String oauth2ClientJackson2ModuleClass = "org.springframework.security.oauth2.client.jackson2.OAuth2ClientJackson2Module";

	private static final String javaTimeJackson2ModuleClass = "com.fasterxml.jackson.datatype.jsr310.JavaTimeModule";
// ...省略...
}

public class CoreJackson2Module extends SimpleModule{

	public CoreJackson2Module() {
		super(CoreJackson2Module.class.getName(), new Version(1, 0, 0, null, null, null));
	}

	@Override
	public void setupModule(SetupContext context) {
		SecurityJackson2Modules.enableDefaultTyping(context.getOwner());
		context.setMixInAnnotations(AnonymousAuthenticationToken.class, AnonymousAuthenticationTokenMixin.class);
		context.setMixInAnnotations(RememberMeAuthenticationToken.class, RememberMeAuthenticationTokenMixin.class);
		context.setMixInAnnotations(SimpleGrantedAuthority.class, SimpleGrantedAuthorityMixin.class);
		context.setMixInAnnotations(Collections.<Object>unmodifiableSet(Collections.emptySet()).getClass(),
				UnmodifiableSetMixin.class);
		context.setMixInAnnotations(Collections.<Object>unmodifiableList(Collections.emptyList()).getClass(),
				UnmodifiableListMixin.class);
		context.setMixInAnnotations(User.class, UserMixin.class);
		context.setMixInAnnotations(UsernamePasswordAuthenticationToken.class,
				UsernamePasswordAuthenticationTokenMixin.class);
		context.setMixInAnnotations(BadCredentialsException.class, BadCredentialsExceptionMixin.class);
	}
}

顺着List securityModules = SecurityJackson2Modules.getModules(classLoader);这行代码我们一层一层向内跟进发现在CoreJackson2Module中存在context.setMixInAnnotations(User.class, UserMixin.class);这么一行代码,也就是被自定义CustomUser类替换的User。现在我们大体应该明白了异常的意思了,它是让我们为CustomUser设置一个类可以安全地反序列化它,使用Jackson注释或提供Mixin提供显式映射,就像UserMixin.class类似。

解决问题

我们需要对JdbcOAuth2AuthorizationService的属性authorizationParametersMapper在原来的基础上把CustomUser对应反序列化加入authorizationParametersMapper的objectMapper属性中,代码如下,CustomUserMixin可参考UserMixin相关内容我这里照着负责了一份,实际上要根据自己的实际要求来修改,我这里图方便,这样就可以解决异常问题了。

@Bean
	public OAuth2AuthorizationService authorizationService(JdbcTemplate jdbcTemplate,
			RegisteredClientRepository registeredClientRepository) {
		JdbcOAuth2AuthorizationService service = new JdbcOAuth2AuthorizationService(jdbcTemplate,
				registeredClientRepository);
		JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper authorizationRowMapper = new JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper(
				registeredClientRepository);
		authorizationRowMapper.setLobHandler(new DefaultLobHandler());

		ObjectMapper objectMapper = new ObjectMapper();
		ClassLoader classLoader = JdbcOAuth2AuthorizationService.class.getClassLoader();
		List<Module> securityModules = SecurityJackson2Modules.getModules(classLoader);
		objectMapper.registerModules(securityModules);
		objectMapper.registerModule(new OAuth2AuthorizationServerJackson2Module());
		objectMapper.addMixIn(CustomUser.class, CustomUserMixin.class);
		authorizationRowMapper.setObjectMapper(objectMapper);

		service.setAuthorizationRowMapper(authorizationRowMapper);
		return service;
	}
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
@JsonDeserialize(using = CustomUserDeserializer.class)
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE)
@JsonIgnoreProperties(ignoreUnknown = true)
public interface CustomUserMixin {
}
public class CustomUserDeserializer extends JsonDeserializer<User> {

	private static final TypeReference<Set<SimpleGrantedAuthority>> SIMPLE_GRANTED_AUTHORITY_SET = new TypeReference<Set<SimpleGrantedAuthority>>() {
	};

	/**
	 * This method will create {@link User} object. It will ensure successful object
	 * creation even if password key is null in serialized json, because credentials
	 * may be removed from the {@link User} by invoking
	 * {@link User#eraseCredentials()}. In that case there won't be any password key
	 * in serialized json.
	 *
	 * @param jp   the JsonParser
	 * @param ctxt the DeserializationContext
	 * @return the user
	 * @throws IOException             if a exception during IO occurs
	 * @throws JsonProcessingException if an error during JSON processing occurs
	 */
	@Override
	public User deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
		ObjectMapper mapper = (ObjectMapper) jp.getCodec();
		JsonNode jsonNode = mapper.readTree(jp);
		Set<? extends GrantedAuthority> authorities = mapper.convertValue(jsonNode.get("authorities"),
				SIMPLE_GRANTED_AUTHORITY_SET);
		JsonNode passwordNode = readJsonNode(jsonNode, "password");
		String username = readJsonNode(jsonNode, "username").asText();
		String password = passwordNode.asText("");
		boolean enabled = readJsonNode(jsonNode, "enabled").asBoolean();
		boolean accountNonExpired = readJsonNode(jsonNode, "accountNonExpired").asBoolean();
		boolean credentialsNonExpired = readJsonNode(jsonNode, "credentialsNonExpired").asBoolean();
		boolean accountNonLocked = readJsonNode(jsonNode, "accountNonLocked").asBoolean();
		User result = new User(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked,
				authorities);
		if (passwordNode.asText(null) == null) {
			result.eraseCredentials();
		}
		return result;
	}

	private JsonNode readJsonNode(JsonNode jsonNode, String field) {
		return jsonNode.has(field) ? jsonNode.get(field) : MissingNode.getInstance();
	}
}

遇到这个问题简单粗略的记录下,希望对遇见类似问题的小伙伴能有一点点的帮助。

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
引用:Caused by: java.lang.IllegalArgumentException: input == null! at javax.imageio.ImageIO.read(ImageIO.java:1388) at com.pleanwar.fiying.FlyingObject.loadImage(FlyingObject.java:52) at ...。 引用:新导入的项目springboot启动报错 java.lang.IllegalArgumentException: Invalid character found in method name. HTTP method names must be tokens at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:422) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:683) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:745) 。 引用:如果在项目中使用了Maven,则需要加入以下两个依赖,否则会报错 <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.14.RELEASE</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.6.7</version> </dependency> 对于xxl-job异常java.lang.IllegalArgumentException,这个异常通常是由于参数不符合方法要求而引起的。根据提供的引用内容,我无法直接确定具体的错误原因。然而,根据异常信息,你可以尝试检查以下几个方面以解决问题: 1. 检查参数是否为空:请确保传递给相关方法的参数不为空。如果参数为空,可能会导致IllegalArgumentException异常。 2. 检查方法名是否有效:如果你遇到类似于"Invalid character found in method name"这样的异常消息,请确保方法名是有效的HTTP方法名。它们应该是令牌(tokens)。 3. 检查项目中的依赖:如果项目中使用了Maven,请确保添加了所需的依赖项。特别是,检查是否包含了org.springframework:spring-webmvc和com.fasterxml.jackson.core:jackson-core这两个依赖项。 请按照上述步骤逐一检查并排除可能的问题,以解决xxl-job异常java.lang.IllegalArgumentException
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值