Spring Security OAuth2用户存储及API Token使用配置求助
Spring WebFlux Security OAuth2 实现方案
以下是满足你需求的完整配置与代码示例,基于Google/GitHub OAuth2登录,包含用户信息持久化、Token管理及资源服务器调用逻辑:
1. 核心依赖配置
在pom.xml中添加必要依赖(Gradle可自行转换格式):
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-client</artifactId> </dependency> <!-- 以Reactive MongoDB为例,若用JPA替换为spring-boot-starter-data-jpa --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId> </dependency> </dependencies>
2. 自定义用户实体与数据仓库
创建与数据库表关联的用户实体,存储OAuth2授权信息:
import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; @Document(collection = "users") public class AppUser { @Id private String id; private String provider; // 授权提供者:google/github/vk private String providerId; // 第三方平台用户ID private String username; private String email; private String avatarUrl; // 构造器、getter、setter省略 }
对应的Reactive数据仓库:
import org.springframework.data.repository.reactive.ReactiveCrudRepository; import reactor.core.publisher.Mono; public interface AppUserRepository extends ReactiveCrudRepository<AppUser, String> { Mono<AppUser> findByProviderAndProviderId(String provider, String providerId); }
3. 自定义OAuth2用户服务(处理用户存储)
实现ReactiveOAuth2UserService,在用户登录成功后将第三方用户信息同步到本地数据库:
import org.springframework.security.oauth2.client.userinfo.ReactiveOAuth2UserService; import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; import org.springframework.security.oauth2.core.user.OAuth2User; import reactor.core.publisher.Mono; @Component public class CustomReactiveOAuth2UserService implements ReactiveOAuth2UserService<OAuth2UserRequest, OAuth2User> { private final AppUserRepository userRepository; public CustomReactiveOAuth2UserService(AppUserRepository userRepository) { this.userRepository = userRepository; } @Override public Mono<OAuth2User> loadUser(OAuth2UserRequest userRequest) { ReactiveOAuth2UserService<OAuth2UserRequest, OAuth2User> delegate = new DefaultReactiveOAuth2UserService(); return delegate.loadUser(userRequest) .flatMap(oAuth2User -> { String provider = userRequest.getClientRegistration().getRegistrationId(); String providerId = oAuth2User.getName(); return userRepository.findByProviderAndProviderId(provider, providerId) .switchIfEmpty(Mono.defer(() -> { AppUser newUser = new AppUser(); newUser.setProvider(provider); newUser.setProviderId(providerId); newUser.setUsername(oAuth2User.getAttribute("name")); newUser.setEmail(oAuth2User.getAttribute("email")); newUser.setAvatarUrl(oAuth2User.getAttribute("picture")); return userRepository.save(newUser); })) .thenReturn(oAuth2User); }); } }
4. 调整Security配置
更新安全配置,指定自定义用户服务并完善OAuth2登录逻辑:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; import org.springframework.security.config.web.server.ServerHttpSecurity; import org.springframework.security.web.server.SecurityWebFilterChain; @Configuration @EnableWebFluxSecurity public class OAuth2LoginSecurityConfig { private final CustomReactiveOAuth2UserService customOAuth2UserService; public OAuth2LoginSecurityConfig(CustomReactiveOAuth2UserService customOAuth2UserService) { this.customOAuth2UserService = customOAuth2UserService; } @Bean public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { http .authorizeExchange(exchanges -> exchanges .anyExchange().authenticated() ) .oauth2Login(oauth2 -> oauth2 .userInfoEndpoint(userInfo -> userInfo .userService(customOAuth2UserService) ) ) .logout(logout -> logout .logoutSuccessUrl("/") ) .csrf(csrf -> csrf.disable()); // 根据实际场景调整CSRF策略 return http.build(); } }
5. 配置OAuth2客户端信息
在application.yml中添加Google/GitHub的客户端配置(需提前在对应平台创建OAuth应用):
spring: security: oauth2: client: registration: google: client-id: YOUR_GOOGLE_CLIENT_ID client-secret: YOUR_GOOGLE_CLIENT_SECRET scope: openid,email,profile github: client-id: YOUR_GITHUB_CLIENT_ID client-secret: YOUR_GITHUB_CLIENT_SECRET scope: user:email,read:user provider: # 后续切换VK时添加以下配置 vk: authorization-uri: https://oauth.vk.com/authorize token-uri: https://oauth.vk.com/access_token user-info-uri: https://api.vk.com/method/users.get?fields=photo_max,email user-name-attribute: response
6. Token管理与资源服务器调用
6.1 获取已保存的Token
Spring Security默认通过ReactiveOAuth2AuthorizedClientService保存用户Token,可直接注入获取:
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService; import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Mono; @RestController public class TokenController { private final ReactiveOAuth2AuthorizedClientService authorizedClientService; public TokenController(ReactiveOAuth2AuthorizedClientService authorizedClientService) { this.authorizedClientService = authorizedClientService; } @GetMapping("/token") public Mono<String> getToken(OAuth2AuthenticationToken authentication) { return authorizedClientService.loadAuthorizedClient( authentication.getAuthorizedClientRegistrationId(), authentication.getName() ) .map(authorizedClient -> authorizedClient.getAccessToken().getTokenValue()); } }
6.2 自动携带Token调用资源服务器
配置WebClient实现自动在请求头中携带OAuth2 Token:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction; import org.springframework.web.reactive.function.client.WebClient; @Configuration public class WebClientConfig { @Bean public WebClient webClient(ReactiveClientRegistrationRepository clientRegistrationRepository) { ServerOAuth2AuthorizedClientExchangeFilterFunction oauth2Filter = new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrationRepository); oauth2Filter.setDefaultOAuth2AuthorizedClient(true); return WebClient.builder() .filter(oauth2Filter) .build(); } }
使用该WebClient调用资源服务器API:
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; @RestController public class ResourceController { private final WebClient webClient; public ResourceController(WebClient webClient) { this.webClient = webClient; } @GetMapping("/call-github-api") public Mono<String> callGithubApi() { return webClient.get() .uri("https://api.github.com/user") .retrieve() .bodyToMono(String.class); } }
内容的提问来源于stack exchange,提问作者Roman Anokhin
相关产品推荐
相关产品推荐

