【问题标题】:Disable CSRF in spring-boot application with OAuth2 SSO使用 OAuth2 SSO 在 spring-boot 应用程序中禁用 CSRF
【发布时间】:2017-11-08 02:50:31
【问题描述】:

我有一个 spring-boot 服务,它使用 OpenID Connect/OAuth2 使用 Okta 平台 API 对用户进行身份验证。当用户尝试访问我的服务时,他们会被重定向到 Okta 登录页面并进行身份验证,然后 Okta 会将他们重定向回我的服务。

这是我的 pom.xml 的相关部分

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-oauth2</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-security</artifactId>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

这是我的控制器代码:

@RestController
@EnableOAuth2Sso
@SpringBootApplication
public class Application {

    @RequestMapping(path = "/", method = RequestMethod.GET)
    public String home(Authentication auth) {
        return "Home: " + auth.getName();
    }

    @RequestMapping(path = "/app", method = RequestMethod.POST)
    public String app(Authentication auth) {
        return "App: " + auth.getName();
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

这对于第一个 GET 控制器方法非常有效,但对于第二个 POST 方法,我的服务要求我提供 CSRF 令牌。我想完全禁用 CSRF 检查,所以我将其添加到我的应用中

@Configuration
@EnableOAuth2Sso
public class Config extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
    }
}

但是,添加上述配置后,我的服务停止使用 Okta 对用户进行身份验证(不再将未经身份验证的请求重定向到 Okta)。直接调用带空参数的 home() 方法。

我按照这篇博文创建了我的服务https://developer.okta.com/blog/2017/03/21/spring-boot-oauth

如何在 Okta 仍然使用 OAuth2 SSO 身份验证的同时完全禁用 CSRF?

【问题讨论】:

  • 您是否尝试过将javax.security.Principal 注入您的home() 方法而不是Authentication
  • @danze 你解决了吗?如果是这样,请发布答案..

标签: java spring-boot oauth-2.0 csrf okta-api


【解决方案1】:

我遇到了完全相同的问题。在深入研究了 HttpSecurity 类的工作原理后,我修改了 configure() 函数,如下所示:

    @EnableWebSecurity
public static class WebSecurityConfig extends WebSecurityConfigurerAdapter
{
    @Override
    protected void configure(HttpSecurity http) throws Exception
    {
        http.authorizeRequests().anyRequest().authenticated().and().oauth2Login().and().csrf().disable();
    }
}

添加构建器子句 authorizeRequests().anyRequest().authenticated().and().oauth2Login() 强制控制器通过 OAuth 身份验证拦截请求。您会在 Spring HttpSecurity.java 源代码中找到完整的文档。

只是为了确保我修改了所有 REST 端点方法以将令牌作为参数包含在内,并且我可以在 configure() 方法的原始版本中看到令牌为空,但是一旦我添加了额外的子句,令牌就会被包含在内.

【讨论】:

    【解决方案2】:

    您只需为您的 /app 端点禁用 CSRF 令牌。试试这个:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.mvcMatcher("/app").csrf().disable();
    }
    

    【讨论】:

      【解决方案3】:
      @Configuration
      @EnableOAuth2Sso
      public class Config extends WebSecurityConfigurerAdapter {
      
          @Override
          public void configure(HttpSecurity http) throws Exception {
              http.csrf().disable();
          }
      }
      

      这对我不起作用。相反,我为每个帖子请求添加了 csrf 标头。 这是获取 csrf 令牌的代码。

      如果您使用的是 thymeleaf,则添加以下内容以在您的 .html 文件中获取 CSRF 令牌

      <html xmlns:th="http://www.thymeleaf.org">
      <script th:inline="javascript">
      function getToken(){
              var _csrf_token = [[${_csrf.token}]] ;
              var _csrf_param_name = [[${_csrf.parameterName}]];
              console.log(_csrf_token);
              return _csrf_token;
          }
      </script>
      </html>
      

      然后将其作为标头放入您的 ajax 请求中

      function sampleFunc(url, token) {
      
      
              $.ajax({
                  type : 'POST',
                  contentType : "application/json",
                  url : '/storeTokens',
                  beforeSend : function(xhr) {
                      xhr.setRequestHeader('X-CSRF-TOKEN', token);
                  },
                  data : jsonObject
              // dataType : 'html'
              }).done(function(data) {
                  console.log("success");
      
              }).fail(function(jqXhr) {
                  var a = jqXhr;
              });
      
          }
      

      这对我有用..

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-02-21
        • 2016-06-19
        • 2015-11-30
        • 1970-01-01
        • 2020-12-22
        • 2017-09-05
        • 2019-07-11
        • 2016-07-16
        相关资源
        最近更新 更多