使用 Spring Security 在 Spring Boot 应用程序中添加对多租户的支持

Joy*_*Joy 7 spring spring-security oauth-2.0 spring-boot

我是 Spring Security 和 Oauth2 的新手。在我的 Spring Boot 应用程序中,我已经为一个租户实现了 OAuth2 身份验证。现在我正在尝试在我的 Spring Boot 应用程序中进行多租户。从上一篇文章的答案:OAUTH2 user service with Custom Authentication Providers,我实现了两种安全配置以支持两个租户:Tenant1如下Tenant2

自定义OAuth2用户服务如下:

  @Component
  public class CustomOAuth2UserService extends DefaultOAuth2UserService {

     private UserRepository userRepository;

     @Autowired
     public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
     }

    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        ...
    }
 }
Run Code Online (Sandbox Code Playgroud)

租户1安全配置如下:

@Configuration
public class Tenant1SecurityConfiguration extends WebSecurityConfigurerAdapter {
  private final CustomOAuth2UserService customOAuth2UserService;    

  public SecurityConfiguration(CustomOAuth2UserService customOAuth2UserService) {
    this.customOAuth2UserService = customOAuth2UserService;
  }

  public void configure(HttpSecurity http) throws Exception {
    http
        .csrf().disable()
        .authorizeRequests()
            .antMatchers("/login**").permitAll()
            .antMatchers("/manage/**").permitAll()
            .antMatchers("/api/auth-info").permitAll()
            .antMatchers("/api/**").authenticated()
            .antMatchers("/management/health").permitAll()
            .antMatchers("/management/info").permitAll()
            .antMatchers("/management/prometheus").permitAll()
            .antMatchers("/management/**").hasAuthority("ADMIN")
            .antMatchers("/tenant1/**").authenticated()
            .and()
        .oauth2Login()
            .userInfoEndpoint().userService(oauth2UserService());
    http
        .cors().disable();
  }

  private OAuth2UserService<OAuth2UserRequest, OAuth2User> oauth2UserService() {
    return customOAuth2UserService;
  }
}
Run Code Online (Sandbox Code Playgroud)

租户2安全配置如下:

@Order(90)
@Configuration
public class Tenant2SecurityConfiguration extends WebSecurityConfigurerAdapter {
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
        .requestMatcher(new AntPathRequestMatcher("/tenant2/**"))
        .csrf().disable()
        .authorizeRequests()
            .antMatchers("/tenant2/**").hasAuthority("USER")
            .and()
        .httpBasic();
    http
        .cors().disable();
  }

  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth
        .inMemoryAuthentication()
            .withUser("user")
            .password("password")
            .roles("USER");
  }
}
Run Code Online (Sandbox Code Playgroud)

应用程序属性如下:

clientApp.name=myapp
spring.security.oauth2.client.registration.keycloak.client-id=abcd
spring.security.oauth2.client.registration.keycloak.client-name=Auth Server
spring.security.oauth2.client.registration.keycloak.scope=api
spring.security.oauth2.client.registration.keycloak.provider=keycloak
spring.security.oauth2.client.registration.keycloak.client-authentication-method=basic
spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code
myapp.oauth2.path=https://my.app.com/oauth2/
spring.security.oauth2.client.provider.keycloak.token-uri=${myapp.oauth2.path}token
spring.security.oauth2.client.provider.keycloak.authorization-uri=${myapp.oauth2.path}authorize
spring.security.oauth2.client.provider.keycloak.user-info-uri=${myapp.oauth2.path}userinfo
spring.security.oauth2.client.provider.keycloak.user-name-attribute=name
Run Code Online (Sandbox Code Playgroud)

基本上,我的应用程序的目的是B2B。因此,如果我想加入一个新的业务实体B作为我的应用程序的租户,插入其身份验证提供程序,其所有现有用户都应该得到无缝身份验证。

因此,鉴于上述情况,我想到了如下方法(尽管我不确定这是否是最好的方法):

  1. 所有租户可以有一个端点,即无论租户如何,所有用户都可以有一个公共登录页面。在此登录页面上,可以规定用户仅输入电子邮件ID。
  2. 租户 ID 可以根据用户输入的电子邮件 ID 确定。
  3. 根据租户 ID,调用关联租户 ID 的身份验证提供程序以验证关联租户的用户。
  4. 身份验证成功后,重定向到关联租户的主页,如下所示:https://my.app.com/<tenant-id>/

除了上述内容之外,我还想构建一个设置,其中我的应用程序有相当多的租户,例如 40 个租户,其中 20 个租户使用 OAuth2,10 个租户使用基本身份验证,10 个租户使用表单登录。

在这里,为了实现上述类型的功能,从Spring Security 的多租户看来,我必须支持一种身份验证方法,将租户 ID 添加到身份验证令牌,然后根据需要创建到其他身份验证方法的适配器。

但是,在这方面,到目前为止,我在任何帖子中都没有找到任何关于我应该在现有代码库中进行哪些更改才能实现这一目标的具体想法。

有人可以帮忙吗?