我正在尝试使用 OAuth 2.0 将 Spring 应用程序与 Spring Boot 版本 3 中的 Spring Security 集成,如果使用客户端凭据,它工作正常并生成访问令牌,但我需要使用密码凭据获取访问令牌,即,我需要使用登录用户详细信息而不是客户详细信息。在 Spring Boot 3 的更新版本中,它到处都使用 open id,但我希望在不使用 open id connect 的情况下完成它。
我期待适当的结果,它允许通过在更新的 Spring Boot 版本 3 中使用 OAuth 2.0 在 Spring Security 中生成访问令牌来使用密码凭据访问应用程序,就像在 Spring Boot 版本 2.6.1 中一样。给我一个使用邮递员的例子。
spring.security.oauth2.client.registration.client-app.client-id=test
spring.security.oauth2.client.registration.client-app.client-secret=111111
spring.security.oauth2.client.registration.client-app.redirect-uri={baseUrl}/login/oauth2/code/{registrationId}
spring.security.oauth2.client.registration.client-app.authorization-grant-type=password
spring.security.oauth2.client.registration.client-app.scope=message.read,message.write
spring.security.oauth2.client.provider.client-app.authorization-uri=${sso.host}/oauth/authorize
spring.security.oauth2.client.provider.client-app.token-uri=${sso.host}/oauth/token
spring.security.oauth2.client.provider.client-app.user-info-uri=${gateway.host}/api/user/current
spring.security.oauth2.client.provider.client-app.user-name-attribute=data
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.csrf(AbstractHttpConfigurer::disable)
.formLogin(Customizer.withDefaults())
.authorizeHttpRequests(c -> c.anyRequest().authenticated())
.build();
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "spring.security.oauth2.client.registration",name = "client-app.authorization-grant-type",havingValue = "password")
public class CustomAuthenticationProvider implements AuthenticationProvider {
private static final String CLIENT_KEY = "client-app";
private final OAuth2AuthorizedClientRepository authorizedClientRepository;
private final ClientRegistrationRepository clientRegistrationRepository;
private final DefaultOAuth2UserService defaultOAuth2UserService = new DefaultOAuth2UserService();
private final PasswordOAuth2AuthorizedClientProvider provider = new PasswordOAuth2AuthorizedClientProvider();
private final AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
public CustomAuthenticationProvider(OAuth2AuthorizedClientRepository authorizedClientRepository,ClientRegistrationRepository clientRegistrationRepository) {
this.authorizedClientRepository = authorizedClientRepository;
this.clientRegistrationRepository = clientRegistrationRepository;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
ClientRegistration clientRegistration = clientRegistrationRepository.findByRegistrationId(CLIENT_KEY);
OAuth2AuthorizationContext context = OAuth2AuthorizationContext.withClientRegistration(clientRegistration)
.attribute(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME,authentication.getName())
.attribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME,authentication.getCredentials().toString())
.principal(authentication)
.build();
OAuth2AuthorizedClient authorizedClient = provider.authorize(context);
OAuth2UserRequest userRequest = new OAuth2UserRequest(clientRegistration,authorizedClient.getAccessToken());
OAuth2User oAuth2User = defaultOAuth2UserService.loadUser(userRequest);
OAuth2AuthenticationToken oauth2Authentication = new OAuth2AuthenticationToken(oAuth2User, oAuth2User.getAuthorities(),authorizedClient.getClientRegistration().getRegistrationId());
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = attributes.getRequest();
oauth2Authentication.setDetails(authenticationDetailsSource.buildDetails(request));
authorizedClientRepository.saveAuthorizedClient(authorizedClient, oauth2Authentication, request, attributes.getResponse());
return oauth2Authentication;
}
@Override
public boolean supports(Class<?> authentication) {
return UsernamePasswordAuthenticationToken.class == authentication;
}
}
“PasswordOAuth2AuthorizedClientProvider”在建议的答案中已被弃用。