如何在Spring Cloud Gateway中使用Spring Security生成和传递路由的CSRF令牌。

huangapple go评论90阅读模式
英文:

How to generate and pass CSRF token for a route in spring cloud gateway with Spring Security

问题

我正在尝试使用OktaSpring Cloud GatewaySpring Security实现基于OAuth2的身份验证。我想要实现的目标是,我希望Spring Cloud Gateway的某个路由对所有人都可用,无需身份验证。我知道Spring Cloud Gateway使用WebFlux,所以我正在配置Spring Security。我在Spring Cloud Gateway中有三个路由。

  • /auth
  • /doctors
  • /patients

我希望这些/auth/**路由中的任何一个都对所有人可用,因为用户在这里注册,所以我不能在那里放置身份验证。对于另外两个/doctors/**/patients/**,我希望进行身份验证和授权。在Cloud Gateway的SecurityConfig中,我试图实现相同的目标。目前,我已经创建了以下配置:

package com.sb.projects.medica.gateway.config;

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 SecurityConfig {
    @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity httpSecurity) {
        httpSecurity.authorizeExchange(exchanges -> {
            exchanges.pathMatchers("/doctor/**", "/patient/**").authenticated();
            exchanges.pathMatchers("/auth/**").permitAll();
        }).oauth2Client().and().oauth2ResourceServer().jwt();
        return httpSecurity.build();
    }
}

但似乎不起作用。当我尝试访问/auth/**的任何路由时,我收到以下错误消息:

未找到预期的CSRF令牌

如何解决此错误?如何创建CSRF令牌并将其发送到前端?

英文:

I'm trying to implement Oauth2 based authentication using Okta, Spring Cloud Gateway & Spring Security. The objective that I want to achieve is I want a route of spring cloud gateway to be available for all without any authentication. I know spring cloud gateway uses WebFlux. So according to that only I'm configuring Spring Security. I have three routes in spring cloud gateway.

  • /auth
  • /doctors
  • /patients

I want any of these /auth/** routes should be available to all because here my users signup so I can not put authentication there. For the other two /doctors/** and /patients/** I want authentication and Authorisation. In the SecurityConfig in cloud gateway I'm trying to achieve the same. Currently I have made this config:

    package com.sb.projects.medica.gateway.config;
    
    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 SecurityConfig {
        @Bean
        public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity httpSecurity) {
            httpSecurity.authorizeExchange(exchanges -> {
                exchanges.pathMatchers("/doctor/**", "/patient/**").authenticated();
                exchanges.pathMatchers("/auth/**").permitAll();
            }).oauth2Client().and().oauth2ResourceServer().jwt();
            return httpSecurity.build();
        }
    }

But it does not seem to work. When I try to hit any route of /auth/** I get
> An expected CSRF token cannot be found

How can I solve this error. How can I create a csrf token and send it to frontend

答案1

得分: 1

您显然刚刚开始配置CSRF。我建议您从Spring文档开始。真的,甚至在阅读本答案的其余部分之前仔细阅读它。

网关后面的REST API可能可以配置为"stateless"(在Servlet中是http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS),在响应式应用中是http.securityContextRepository(NoOpServerSecurityContextRepository.getInstance())),因此可以禁用CSRF保护(http.csrf().disable())。然后,您可以使用OAuth2授权配置Postman并直接查询API(而不是通过网关)。

根据您的React前端配置为OAuth2公共客户端还是网关作为Backend For Frontend(OAuth2机密客户端,带有TokenRelay过滤器),对CSRF保护的需求有很大的不同:

  • 在第一种情况下,网关可以对安全性保持透明,因为它既不处理登录也不处理登出(这两者都由React应用中的OAuth2客户端库完成),也不处理与用户会话相关的任何内容,因此不需要关注CSRF。
  • 在第二种情况下,网关必须维护授权码流程的会话,以便TokenRelay过滤器能够正常工作(将OAuth2令牌与每个浏览器会话关联)。因此,必须启用CSRF,而您的应用是基于JavaScript的,需要使用Cookie存储库(在响应式应用程序中是http.csrf().csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse()))。然后,您需要配置前端将CSRF令牌(作为Cookie接收)作为X-XSRF-TOKEN标头发送(如果您希望通过网关发送请求而不是直接查询API,则对Postman也有相同的要求)。
英文:

You are obviously just beginning your journey to CSRF configuration. I recommand you start with the Spring documentation. Like really. Read it carefully even before the rest of this answer.

The REST API(s) behind the gateway can probably be configured as "stateless" (http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) in a servlet or http.securityContextRepository(NoOpServerSecurityContextRepository.getInstance()) in a reactive app) and, as a consequence, CSRF protection can be disabled on it (http.csrf().disable()). You then configure Postman with OAuth2 authorization and query the API directly (not through the gateway).

Depending on your React frontend being configured as an OAuth2 public client or the gateway as a Backend For Frontend (OAuth2 confidential client with TokenRelay filter), the needs for CSRF protection are quite different:

  • in the first case, the gateway can be transparent to security and, as it handles neither login nor logout (both are done by the OAuth2 client lib in React app), nor anything related to user session, CSRF is not a concern

  • in the second case, the gateway has to maintain sessions for authorization-code flow to succeed and for the TokenRelay filter to work (keep OAuth2 tokens associated with each browser session). As a consequence, CSRF must be enabled and, as your app is Javascript based, with Cookie repo (http.csrf().csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse()); on a reactive application like spring-cloud-gateway). You'll then have to configure your frontend to send the CSRF token (received as cookie) as X-XSRF-TOKEN header (same requirement for Postman if you want to send requests through the gateway instead of querying the API(s) directly).

huangapple
  • 本文由 发表于 2023年3月7日 22:34:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/75663325.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定