Spring Boot OAuth2 - Keycloak - 不同端点的多个领域

问题描述 投票:0回答:1

我对 Spring Boot 和 Keycloak 的多领域使用有疑问。

我在我的应用程序中配置 OAuth2 有 2 个这样的领域:

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: http://localhost:8080/auth/realms/realmuser
      client:
        provider:
          realmuser:
            props: ...

          realmadmin:
            props: ...

        registration:
          realmuser:
            props: ...

          realmadmin:
            props: ...

Spring Security 涵盖了我的应用程序中的多个端点。

当我向他们中的任何一个发出请求时,我会看到 Spring OAuth2 登录页面,建议我在其中选择“realmuser”或“realmadmin”进行登录。之后一切正常。

但我的目标是按领域划分端点。

例如,我希望将端点“/v1/admin/etc..”重定向到“realmadmin”,将端点“/v1/user/etc..”立即重定向到“realmuser”,即没有 Spring OAuth2 登录页面。

有什么办法可以达到这个目的吗?

我的安全配置:

  @Bean
  public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.authorizeRequests()
        .antMatchers("/v1/*")
        .hasRole("USER")
        .anyRequest()
        .authenticated()
        .and()
        .cors()
        .and()
        .csrf()
        .disable();
    http.oauth2Login()
        .and()
        .logout()
        .addLogoutHandler(keycloakLogoutHandler)
        .logoutSuccessUrl("/");
    http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
    return http.build();
  }

我尝试做的事情:

  • 使用 JwtIssuerAuthenticationManagerResolver 通过声明解决租户,如 docs.spring.io - Multinenancy OAuth 2.0 资源服务器中所述

  • 使用注解@RegisteredOAuth2AuthorizedClient

  • 更新 SecurityConfig

    http.oauth2Login(oauth2Login ->
        oauth2Login
            .authorizationEndpoint(authorizationEndpoint ->
                authorizationEndpoint
                    .baseUri("/oauth2/authorization")
                    .authorizationRequestResolver(new CustomAuthorizationRequestResolver("/oauth2/authorization/realmuser",
                        "/oauth2/authorization/realmadmin", clientRegistrationRepository()))
            )
    )

然后创建类

{

CustomAuthorizationRequestResolver implements OAuth2AuthorizationRequestResolver

//...


    @Override
    public OAuth2AuthorizationRequest resolve(HttpServletRequest request) {
      String authorizationUri;
      if (request.getServletPath().startsWith("/v1/admin")) {
        authorizationUri = adminAuthorizationUri;
      } else if (request.getServletPath().startsWith("/v1/user")) {
        authorizationUri = userAuthorizationUri;
      } else {
        authorizationUri = "/oauth2/authorize";
      }
      OAuth2AuthorizationRequest authorizationRequest = defaultAuthorizationRequestResolver.resolve(request);
      return authorizationRequest != null ? OAuth2AuthorizationRequest.from(authorizationRequest)
          .authorizationUri(authorizationUri)
          .build() : null;
    }

    @Override
    public OAuth2AuthorizationRequest resolve(HttpServletRequest request, String clientRegistrationId) {
      return defaultAuthorizationRequestResolver.resolve(request, clientRegistrationId);
    }

}

他们都没有帮助我解决我的问题。

keycloak openid multi-tenant
1个回答
0
投票

客户端和资源服务器配置非常不同:对 OAuth2 客户端的请求使用会话保护,而对资源服务器的请求使用访问令牌保护(这使得摆脱会话成为可能)。

oauth2Login
logout
和所有
spring.security.oauth2.client
属性都是客户端特征。在上面的配置中,客户端配置启用并需要会话。 在 OAuth2 客户端上禁用 CSRF 保护是非常不安全的,不应该这样做.

如果您检查浏览器发送的请求,您将找不到任何访问令牌。您只会找到会话 cookie。您必须使用基于 Javascript 的框架(Angular、Vue、React、NextJS 等)并将其配置为公共 OAuth2 客户端(在库的帮助下),以便使用访问令牌授权浏览器请求。另一种(最近首选的)保护从 Javascript 应用程序到资源服务器的请求的方法是在服务器上插入一个中间件(Backend FFrontend)以从 Javascript 代码中隐藏 OAuth2 令牌。在此架构中,BFF 是 OAuth2 客户端,负责在将请求从浏览器转发到 REST API 之前用访问令牌替换会话 cookie。

资源服务器不关心登录、注销或如何获取或保留令牌。对它来说重要的是一个请求是否被访问令牌授权,这个访问令牌是否有效,它是否是由它信任的授权服务器发出的,以及他是否应该根据令牌声明授予对所请求资源的访问权限。

上面的资源服务器配置大部分是无效的,只会接受

realmuser
发出的令牌(前提是您编写了一个发送此类令牌的客户端,因为如上所述,如果您的浏览器使用Spring的
oauth2Login
,则不会) .

所以,您应该回答的第一个问题是:

  • 您是否正在公开要使用访问令牌保护的 REST API?如果是,那些端点应该配置 OAuth2 资源服务器安全性
  • 您是否公开模板化 UI(Thymeleaf 或其他)?如果是,那些端点应该配置 OAuth2 客户端安全
  • 您是否公开了 REST API 和 UI 来查询它?在这种情况下,我强烈建议您将客户端和资源服务器配置拆分为不同的安全过滤器链(一个具有基于会话的客户端安全性,另一个具有基于访问令牌的资源服务器安全性)

一旦你对 OAuth2 客户端和资源服务器的需求有了更清晰的认识(并了解两者的安全性有多么不同),我建议你参考我写的教程,都支持多个授权服务器(或领域) .

© www.soinside.com 2019 - 2024. All rights reserved.