我已经使用org.springframework.security:spring-security-oauth2-authorization-server:0.2.2
创建了我的授权服务器,使用org.springframework.boot:spring-boot-starter-oauth2-client
创建了我的客户端。用户能够成功登录和注销,但是,在测试过程中,我注意到如果我成功登录,然后在未注销的情况下重新启动客户端(而不是服务器),并尝试再次登录,服务器会在无休止的重定向循环中抛出以下错误
java.lang.IllegalArgumentException: The class with org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken and name of org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken 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,但它的解决方案对我不起作用。我还尝试了在这个链接www.example.com中描述的不同解决方案https://github.com/spring-projects/spring-authorization-server/issues/397#issuecomment-900148920,并修改了我的授权服务器代码如下:-这是我的JacksonConfigs
@Configuration
public class JacksonConfiguration {
/**
* Support for Java date and time API.
*
* @return the corresponding Jackson module.
*/
@Bean
public JavaTimeModule javaTimeModule() {
return new JavaTimeModule();
}
@Bean
public Jdk8Module jdk8TimeModule() {
return new Jdk8Module();
}
/*
* Support for Hibernate types in Jackson.
*/
@Bean
public Hibernate5Module hibernate5Module() {
return new Hibernate5Module();
}
/*
* Module for serialization/deserialization of RFC7807 Problem.
*/
@Bean
public ProblemModule problemModule() {
return new ProblemModule();
}
/*
* Module for serialization/deserialization of ConstraintViolationProblem.
*/
@Bean
public ConstraintViolationProblemModule constraintViolationProblemModule() {
return new ConstraintViolationProblemModule();
}
/**
* To (de)serialize a BadCredentialsException, use CoreJackson2Module:
*/
@Bean
public CoreJackson2Module coreJackson2Module() {
return new CoreJackson2Module();
}
@Bean
@Primary
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(coreJackson2Module());
mapper.registerModule(javaTimeModule());
mapper.registerModule(jdk8TimeModule());
mapper.registerModule(hibernate5Module());
mapper.registerModule(problemModule());
mapper.registerModule(constraintViolationProblemModule());
return mapper;
}
}
这是我的授权服务器配置
@Configuration(proxyBeanMethods = false)
public class AuthServerConfig {
private final DataSource dataSource;
private final AuthProperties authProps;
private final PasswordEncoder encoder;
public AuthServerConfig(DataSource dataSource, AuthProperties authProps, PasswordEncoder encoder) {
this.dataSource = dataSource;
this.authProps = authProps;
this.encoder = encoder;
}
@Bean
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource);
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer<HttpSecurity> authorizationServerConfigurer =
new OAuth2AuthorizationServerConfigurer<>();
authorizationServerConfigurer.tokenRevocationEndpoint(tokenRevocationEndpoint -> tokenRevocationEndpoint
.revocationResponseHandler((request, response, authentication) -> {
Assert.notNull(request, "HttpServletRequest required");
HttpSession session = request.getSession(false);
if (!Objects.isNull(session)) {
session.removeAttribute("SPRING_SECURITY_CONTEXT");
session.invalidate();
}
SecurityContextHolder.getContext().setAuthentication(null);
SecurityContextHolder.clearContext();
response.setStatus(HttpStatus.OK.value());
})
);
RequestMatcher endpointsMatcher = authorizationServerConfigurer.getEndpointsMatcher();
http
.requestMatcher(endpointsMatcher)
.authorizeRequests(authorizeRequests -> authorizeRequests.anyRequest().authenticated())
.csrf(csrf -> csrf.ignoringRequestMatchers(endpointsMatcher))
.apply(authorizationServerConfigurer);
return http.formLogin(Customizer.withDefaults()).build();
}
@Bean
public RegisteredClientRepository registeredClientRepository(JdbcTemplate jdbcTemplate, TokenSettings tokenSettings) {
JdbcRegisteredClientRepository clientRepository = new JdbcRegisteredClientRepository(jdbcTemplate);
RegisteredClient webClient = RegisteredClient.withId("98a9104c-a9c7-4d7c-ad03-ec61bcfeab36")
.clientId(authProps.getClientId())
.clientName(authProps.getClientName())
.clientSecret(encoder.encode(authProps.getClientSecret()))
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.redirectUri("http://127.0.0.1:8000/login/oauth2/code/web-client")
.scope(OidcScopes.OPENID)
.scope(OidcScopes.PROFILE)
.tokenSettings(tokenSettings)
.build();
clientRepository.save(webClient);
return clientRepository;
}
@Bean
public OAuth2AuthorizationService authorizationService(JdbcTemplate jdbcTemplate,
RegisteredClientRepository registeredClientRepository,
ObjectMapper objectMapper) {
JdbcOAuth2AuthorizationService authorizationService =
new JdbcOAuth2AuthorizationService(jdbcTemplate, registeredClientRepository);
JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper rowMapper = new JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper(registeredClientRepository);
ClassLoader classLoader = JdbcOAuth2AuthorizationService.class.getClassLoader();
objectMapper.registerModules(SecurityJackson2Modules.getModules(classLoader));
objectMapper.registerModule(new OAuth2AuthorizationServerJackson2Module());
// You will need to write the Mixin for your class so Jackson can marshall it.
// objectMapper.addMixIn(UserPrincipal .class, UserPrincipalMixin.class);
rowMapper.setObjectMapper(objectMapper);
authorizationService.setAuthorizationRowMapper(rowMapper);
return authorizationService;
}
@Bean
public OAuth2AuthorizationConsentService authorizationConsentService(JdbcTemplate jdbcTemplate,
RegisteredClientRepository registeredClientRepository) {
return new JdbcOAuth2AuthorizationConsentService(jdbcTemplate, registeredClientRepository);
}
@Bean
public JWKSource<SecurityContext> jwkSource() {
RSAKey rsaKey = generateRsa();
JWKSet jwkSet = new JWKSet(rsaKey);
return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
}
private static RSAKey generateRsa() {
KeyPair keyPair = generateRsaKey();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
return new RSAKey.Builder(publicKey)
.privateKey(privateKey)
.keyID(UUID.randomUUID().toString())
.build();
}
private static KeyPair generateRsaKey() {
KeyPair keyPair;
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
keyPair = keyPairGenerator.generateKeyPair();
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
return keyPair;
}
@Bean
public ProviderSettings providerSettings() {
return ProviderSettings.builder()
.issuer(authProps.getIssuerUri())
.build();
}
@Bean
public TokenSettings tokenSettings() {
return TokenSettings.builder()
.accessTokenTimeToLive(Duration.ofDays(1))
.refreshTokenTimeToLive(Duration.ofDays(1))
.build();
}
}
但我仍然面临着同样的问题。
我该如何解决这个问题?任何帮助都是非常感谢的。
2条答案
按热度按时间r7knjye21#
在尝试了不同的解决方案后,这就是我能够解决它的方法。
我将我的
OAuth2AuthorizationService
bean更改为如下所示。这是我的JwtAuthenticationTokenMixin配置
s2j5cfk02#
你不需要创建一个Mixin,因为它已经由授权springboot模块创建好了。
我想您错过了这一行,它是标记mixin注册的地方