这是我想要实现的场景:
我能够正确配置 oauth2 :
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/", "/index").permitAll()
.anyRequest().authenticated())
.oauth2Login(Customizer.withDefaults());
return http.build();
}
现在,当我获取 localhost:8080/ 时,我没有问题,如果我获取例如 localhost:8080/user ,它会正确重定向到 oauth 然后我可以访问该资源。
@Service
@RequiredArgsConstructor(onConstructor = @__(@Lazy))
public class Oauth2UserService extends DefaultOAuth2UserService {
@Override
public OAuth2User loadUser(OAuth2UserRequest oAuth2UserRequest) {
OAuth2User oAuth2User = super.loadUser(oAuth2UserRequest);
return processOAuth2User(oAuth2UserRequest, oAuth2User);
}
private OAuth2User processOAuth2User(OAuth2UserRequest oAuth2UserRequest, OAuth2User oAuth2User) {
System.out.println("user attributes : " + oAuth2User.getAttributes());
System.out.println("access token is " + oAuth2UserRequest.getAccessToken().getTokenValue());
System.out.println(
"refresh token is : " + oAuth2UserRequest.getAdditionalParameters().get(OAuth2ParameterNames.REFRESH_TOKEN));
System.out.println(
"additional parameters are : " + oAuth2UserRequest.getAdditionalParameters());
return oAuth2User;
}
}
但是,当我这样做时,我只检索访问令牌,该令牌的过期时间很短,因此不适合长期更新。刷新令牌为空,附加参数为空映射。 我尝试了几种(很多)用户配置,但似乎没有任何效果(我没有跟踪它,因为我已经尝试了好几天了)。 包括https://stackoverflow.com/a/70548497/23229663
这是我的问题:
@Import({
MyLibReference1.class,
MyLibReference2.class})
您能否将我重定向到不再需要该指南的指南?也就是说,当我将我的 lib 声明为 MainApp 项目的 Maven 依赖项时,它会自动扫描该 lib 的包。我找到了一些线索,但我想我迷路了。虽然这是低优先级的,到目前为止它很乏味但它有效。 (但由于它很乏味,以后会产生错误) 4. 同样不重要,优先级不高,如何将提供程序存储在库中,而不必写入 application.yaml ?
感谢您的宝贵时间:)
链接: 我想实现这个的实际代码:https://github.com/guiguilechat/JCELechat/tree/mevetic/programs/spring/mevetic 主类和导入示例:https://github.com/guiguilechat/JCELechat/blob/mevetic/programs/spring/eveproxy/src/main/java/fr/guiguilechat/jcelechat/programs/spring/eveproxy/EveProxyApp。爪哇 库 Libreference 的示例:https://github.com/guiguilechat/JCELechat/blob/mevetic/libs/spring/mer/src/main/java/fr/guiguilechat/jcelechat/libs/spring/mer/MerReference.java
编辑:我再次研究了另一个解决方案,并且可以使其工作。 作为参考,这里是添加在 SecurityConfig 上的有效代码:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
// actually no change on the filterChain because it's not needed
@Bean
public OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient() {
DefaultAuthorizationCodeTokenResponseClient accessTokenResponseClient = new DefaultAuthorizationCodeTokenResponseClient();
OAuth2AccessTokenResponseHttpMessageConverter tokenResponseHttpMessageConverter = new OAuth2AccessTokenResponseHttpMessageConverter();
tokenResponseHttpMessageConverter.setAccessTokenResponseConverter(new CustomTokenResponseConverter());
RestTemplate restTemplate = new RestTemplate(Arrays.asList(
new FormHttpMessageConverter(), tokenResponseHttpMessageConverter));
restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
accessTokenResponseClient.setRestOperations(restTemplate);
return accessTokenResponseClient;
}
public static class CustomTokenResponseConverter implements
Converter<Map<String, Object>, OAuth2AccessTokenResponse> {
@Override
public OAuth2AccessTokenResponse convert(Map<String, Object> tokenResponseParameters) {
String accessToken = (String) tokenResponseParameters.get(OAuth2ParameterNames.ACCESS_TOKEN);
String refreshToken = (String) tokenResponseParameters.get(OAuth2ParameterNames.REFRESH_TOKEN);
Object expiresInObj = tokenResponseParameters.get(OAuth2ParameterNames.EXPIRES_IN);
long expiresIn = ((Number) expiresInObj).longValue();
Set<String> scopes = Collections.emptySet();
if (tokenResponseParameters.containsKey(OAuth2ParameterNames.SCOPE)) {
String scope = (String) tokenResponseParameters.get(OAuth2ParameterNames.SCOPE);
scopes = Arrays.stream(StringUtils.delimitedListToStringArray(scope, " "))
.collect(Collectors.toSet());
}
return OAuth2AccessTokenResponse.withToken(accessToken)
.tokenType(OAuth2AccessToken.TokenType.BEARER)
.expiresIn(expiresIn)
.scopes(scopes)
.refreshToken(refreshToken)
.additionalParameters(Map.of(OAuth2ParameterNames.REFRESH_TOKEN, refreshToken))
.build();
}
}
}
我遇到的问题是,在另一个答案的代码中,expiresIn是从字符串解析的,但在目前的框架中,它是地图中的一个数字(我猜很长),所以parseLong默默地失败了,我刚刚收到一个错误。
话虽如此,我不确定这是正确的方法。特别是,似乎有几种手动配置会阻止自动配置,否则自动配置会起作用。
好的,这是第一个问题的答案:只需在配置类中拥有 OAuth2AccessTokenResponseClient 的 @Bean :
@Configuration
@EnableWebSecurity
public class SecurityConfig {
// actually no change on the filterChain because it's not needed
@Bean
public OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient() {
DefaultAuthorizationCodeTokenResponseClient accessTokenResponseClient = new DefaultAuthorizationCodeTokenResponseClient();
OAuth2AccessTokenResponseHttpMessageConverter tokenResponseHttpMessageConverter = new OAuth2AccessTokenResponseHttpMessageConverter();
tokenResponseHttpMessageConverter.setAccessTokenResponseConverter(new CustomTokenResponseConverter());
RestTemplate restTemplate = new RestTemplate(Arrays.asList(
new FormHttpMessageConverter(), tokenResponseHttpMessageConverter));
restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
accessTokenResponseClient.setRestOperations(restTemplate);
return accessTokenResponseClient;
}
public static class CustomTokenResponseConverter implements
Converter<Map<String, Object>, OAuth2AccessTokenResponse> {
@Override
public OAuth2AccessTokenResponse convert(Map<String, Object> tokenResponseParameters) {
String accessToken = (String) tokenResponseParameters.get(OAuth2ParameterNames.ACCESS_TOKEN);
String refreshToken = (String) tokenResponseParameters.get(OAuth2ParameterNames.REFRESH_TOKEN);
Object expiresInObj = tokenResponseParameters.get(OAuth2ParameterNames.EXPIRES_IN);
long expiresIn = ((Number) expiresInObj).longValue();
Set<String> scopes = Collections.emptySet();
if (tokenResponseParameters.containsKey(OAuth2ParameterNames.SCOPE)) {
String scope = (String) tokenResponseParameters.get(OAuth2ParameterNames.SCOPE);
scopes = Arrays.stream(StringUtils.delimitedListToStringArray(scope, " "))
.collect(Collectors.toSet());
}
return OAuth2AccessTokenResponse.withToken(accessToken)
.tokenType(OAuth2AccessToken.TokenType.BEARER)
.expiresIn(expiresIn)
.scopes(scopes)
.refreshToken(refreshToken)
.additionalParameters(Map.of(OAuth2ParameterNames.REFRESH_TOKEN, refreshToken))
.build();
}
}
}
这是图书馆的答案:别想旧工厂的事。现在你只需
现在它不起作用,我想我必须强制我的类在 oauth2 自动配置之前加载以提供 bean。稍后再编辑。