简体   繁体   English

Spring WebFlux 安全 OAuth 2.0 用户服务

[英]Spring WebFlux Security OAuth 2.0 User Service

To give some context, I am currently migrating from standard Spring Security 5 (with spring-boot-starter-web ) to spring-webflux - being used with the Spring Cloud Gateway as my API Gateway - which doesn't support spring-boot-starter-web dependencies.为了提供一些背景信息,我目前正在从标准 Spring Security 5(带有spring-boot-starter-web )迁移到spring-webflux - 与 Spring 云网关一起使用,因为我的 ZDB974238714CA8DE1634A7CE1D08 不支持spring-boot-starter-web -boot-starter-web spring-boot-starter-web依赖项。

I have got everything else working with Spring Reactor/Webflux - apart from my OAuth 2.0 User Service (that I had in the previous implementation).除了我的 OAuth 2.0 用户服务(我在之前的实现中拥有)之外,我还可以使用 Spring Reactor/Webflux 进行其他所有工作。 So I have copied the user service over - except I am now unable to reference that from the new Security Configuration.所以我已经复制了用户服务——除了我现在无法从新的安全配置中引用它。

Here's my new Security Configuration:这是我的新安全配置:

@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class SecurityConfig {

  private final OAuth2SuccessHandler oAuth2SuccessHandler;
  private final OAuth2FailureHandler oAuth2FailureHandler;
  private final OAuth2UserService customOAuth2UserService;

  public SecurityConfig(OAuth2SuccessHandler oAuth2SuccessHandler, OAuth2FailureHandler oAuth2FailureHandler, OAuth2UserService customOAuth2UserService) {
    this.oAuth2SuccessHandler = oAuth2SuccessHandler;
    this.oAuth2FailureHandler = oAuth2FailureHandler;
    this.customOAuth2UserService = customOAuth2UserService;
  }

  @Bean
  public TokenAuthenticationFilter tokenAuthenticationFilter() {
    return new TokenAuthenticationFilter();
  }

  @Bean
  public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
  }

  @Bean
  public ReactiveAuthenticationManager reactiveAuthenticationManager(
          UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) {
    UserDetailsRepositoryReactiveAuthenticationManager authenticationManager =
        new UserDetailsRepositoryReactiveAuthenticationManager(userDetailsService);
    authenticationManager.setPasswordEncoder(passwordEncoder);

    return authenticationManager;
  }

  @Bean
  public SecurityWebFilterChain springWebFilterChain(
      ServerHttpSecurity http) {
    http
            .requestCache()
            .requestCache(NoOpServerRequestCache.getInstance())
            .and()
            .securityContextRepository(NoOpServerSecurityContextRepository.getInstance())
            .authorizeExchange()
            .pathMatchers(
                    "/",
                    "/error",
                    "/favicon.ico",
                    "/*/*.png",
                    "/*/*.gif",
                    "/*/*.svg",
                    "/*/*.jpg",
                    "/*/*.html",
                    "/*/*.css",
                    "/*/*.js")
            .permitAll()
            .pathMatchers("/login/*", "/auth/*", "/oauth2/*")
            .permitAll()
            .anyExchange()
            .authenticated()
            .and()
            .oauth2Login()
            .authenticationSuccessHandler(oAuth2SuccessHandler)
            .authenticationFailureHandler(oAuth2FailureHandler)
            .and()
            .formLogin()
            .disable()
            .exceptionHandling()
            .authenticationEntryPoint(new AuthenticationEntryPoint())
            .and()
            .oauth2Client();

    http.addFilterBefore(tokenAuthenticationFilter(), SecurityWebFiltersOrder.AUTHENTICATION);

    return http.build();
  }
}

Here's my OAuth 2.0 Custom User Service这是我的 OAuth 2.0 自定义用户服务

@Service
public class OAuth2UserService extends DefaultOAuth2UserService {

  private final UserDao userDao;

  public OAuth2UserService(UserDao userDao) {
    this.userDao = userDao;
  }

  @Override
  public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
    OAuth2User oAuth2User = super.loadUser(userRequest);

    OAuth2UserInfo oAuth2UserInfo =
            OAuth2UserInfoFactory.getOAuth2UserInfo(
                    userRequest.getClientRegistration().getRegistrationId(), oAuth2User.getAttributes());

    if (StringUtils.isEmpty(oAuth2UserInfo.getEmail())) {
      throw new OAuth2AuthenticationProcessingException("Email not found from any providers");
    }

    /* Find the user by email */
    User user = userDao.findUserByEmail(oAuth2UserInfo.getEmail());

    try {
      if (user == null) throw new OAuth2AuthenticationProcessingException("You must sign up!");

      if (!user.getProvider().equals(AuthProvider.valueOf(userRequest.getClientRegistration().getRegistrationId()))) {
        throw new OAuth2AuthenticationProcessingException(
            "Woah! Looks like you're already signed up with your "
                + user.getProvider().getValue()
                + ". Please use your "
                + user.getProvider().getValue()
                + " account to login.");
      }

      user = registerNewUser(userRequest, oAuth2UserInfo);
    } catch (Exception e) {

    }

    return UserPrincipal.create(user, oAuth2User.getAttributes());
  }

  private User registerNewUser(OAuth2UserRequest oAuth2UserRequest, OAuth2UserInfo oAuth2UserInfo) {
    User user = new User();

    user.setProvider(
            AuthProvider.valueOf(oAuth2UserRequest.getClientRegistration().getRegistrationId()));
    user.setProviderId(oAuth2UserInfo.getId());
    user.setUsername(oAuth2UserInfo.getName());
    user.setEmail(oAuth2UserInfo.getEmail());
    user.setProfilePicture(oAuth2UserInfo.getImageUrl());

    return userDao.save(user);
  }
}

the only difference between that and my old configuration was that I could use this那和我的旧配置之间的唯一区别是我可以使用它

http
    .userInfoEndpoint()
    .userService(customOAuth2UserService)

however, there is no option to use this with the New Security Configuration Options (that I am aware of) - so please answer if you know a way of pointing Spring Security to my Custom User Service.但是,没有选项可以将其与新的安全配置选项(我知道)一起使用 - 因此,如果您知道将 Spring 安全性指向我的自定义用户服务的方法,请回答。

Many Thanks非常感谢

Your Service bean is for the regular OAuth flow.您的服务 bean 用于常规 OAuth 流。 The actual one you want is the WebFlux one, which is ReactiveOAuth2UserService .您想要的实际是 WebFlux 之一,即ReactiveOAuth2UserService

You can verify this for yourself by setting a breakpoint on the ReactiveOAuth2UserService::loadUser method and then authenticating normally.您可以通过在ReactiveOAuth2UserService::loadUser方法上设置断点然后正常进行身份验证来自己验证这一点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM