【问题标题】:AJAX request with Spring Security gives 403 Forbidden带有 Spring Security 的 AJAX 请求给出 403 Forbidden
【发布时间】:2019-09-18 14:18:33
【问题描述】:

我有一个基于 spring boot、spring-security、thymeleaf 的网站,在某些情况下我也使用 ajax。

问题:

我在 Spring Security 中使用表单登录安全性。在浏览器中,登录后我可以使用 rest API (GET),但使用 ajax 它会返回 403,即使我的 ajax 请求在 cookie 中包含会话 ID。

安全配置:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
    .antMatchers("/admin/**").hasRole("ADMIN")
    .antMatchers("/rest/**").hasRole("ADMIN")
            .anyRequest().permitAll()
     .and()
     .formLogin().loginPage("/sign-in-up")
            .loginProcessingUrl("/signInProcess").usernameParameter("phone").and().logout()
            .logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/");

}

REST API 我测试正确。

@RestController
@RequestMapping("rest/categories")
public class CategoriesRest {
@Autowired
private CategoryService categoryService;

@GetMapping("/")
public ResponseEntity<List<Category>> findAll() {
    List<Category> all = categoryService.getAll();
    if (all.isEmpty()) {
        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }
    return new ResponseEntity<>(all, HttpStatus.OK);
}

@GetMapping("/{id}")
public ResponseEntity<Category> findById(@PathVariable int id) {
    Category obj = categoryService.get(id);
    if (obj == null) {
        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }
    return new ResponseEntity<>(obj, HttpStatus.OK);
}

@PostMapping("/")
public ResponseEntity<Category> createMainSlider(@RequestBody Category obj) {
    System.out.println("-------rest Post");

    return new ResponseEntity<>(categoryService.add(obj), HttpStatus.CREATED);
}

@PutMapping("/{id}")
public ResponseEntity<Category> update(@RequestBody Category obj, @PathVariable int id) {
    Category obj1 = categoryService.update(obj);

    System.out.println(obj);
    return new ResponseEntity<>(obj1, HttpStatus.OK);
}

@DeleteMapping("/{id}")
public ResponseEntity<Category> deleteEmp(@PathVariable int id) {
    categoryService.delete(id);
    return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}

}

- 我的 ajax 代码:

$('.deleteBtn').bind('click',function(e){
        e.preventDefault();
        $.ajax({
            type:'DELETE',
            url : "/rest/categories/"+$(e.currentTarget).data('id'),
             xhrFields: {
                  withCredentials: true
               },
             success : function(result) {
                 location.reload();
                 console.log(result);
               },
              error : function(e) {
                alert("Error!")
                console.log("ERROR: ", e);
              }
        })
    })

编辑 [GET] 请求工作正常,但 [PUT,POST,DELETE] 不工作。

【问题讨论】:

  • 您好,Hamod 您是否面临 403 仅针对 `url : "/rest/categories/"+$(e.currentTarget).data('id'),` 其他 API 是否正常工作或给403?
  • 我的意思是,除了 DELETE 方法或所有方法和 API 都面临 403 之外,您是否能够获得响应?
  • 如果您查看从客户端到服务器的请求,Authorization 标头正在设置,它正在发送带有 Base64 编码字符串的基本身份验证。这很可能发生在您的 javascript 中的 withCredentials: true 中。我会尝试删除它,看看会发生什么。
  • 是的,这是真的,我把'withCredentials:true'尝试解决问题,但实际上是同一个问题,我删除它并没有解决
  • @PatelRomil 我发现 [GET] 请求有效,但其他请求无效!!

标签: java ajax spring spring-boot spring-security


【解决方案1】:

为什么.csrf().disable().cors() 有效?

CSRF 代表 跨站请求伪造

简单来说,它是一种随请求一起发送以防止攻击的令牌。为了使用 Spring Security CSRF 保护,我们首先需要确保对任何修改状态的东西使用正确的 HTTP 方法(PATCH、POST、PUT 和 DELETE - 而不是 @ 987654327@).

一些框架通过使用户的会话无效来处理无效的 CSRF 令牌,但这会导致其自身的问题。相反,默认情况下 Spring Security 的 CSRF 保护会产生一个HTTP 403 access denied。

Ajax and JSON Requests

如果您使用的是 JSON,则无法在 HTTP 参数中提交 CSRF 令牌。相反,您可以在 HTTP 标头中提交令牌。一个典型的模式是在元标记中包含 CSRF 令牌

<meta name="_csrf" content="${_csrf.token}"/>
<meta name="_csrf_header" content="${_csrf.headerName}"/>

//jQuery
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");

$(document).ajaxSend(function(e, xhr, options) {
    xhr.setRequestHeader(header, token);
});

【讨论】:

  • 非常感谢..很好的解释:)
  • @MuhammedHamod 欢迎,如果有帮助,您可以接受答案
【解决方案2】:

谢谢大家
我通过禁用 CSRF 解决了这个问题,我添加了这个

.csrf().disable().cors()

所以在我的 spring 安全配置中:

        http.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN").antMatchers("/rest/**").hasRole("ADMIN")
            .anyRequest().permitAll().and().formLogin().loginPage("/sign-in-up")
            .loginProcessingUrl("/signInProcess").usernameParameter("phone").and().logout()
            .logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/")
            .and()
            .csrf().disable().cors();

====== 编辑:
@Patel 给出了有用的解释……感谢他

【讨论】:

  • 您好,我已经为它添加了详细信息。
猜你喜欢
  • 2018-12-13
  • 2015-09-19
  • 1970-01-01
  • 2019-12-21
  • 2021-02-26
  • 2017-11-11
  • 1970-01-01
  • 1970-01-01
  • 2020-08-25
相关资源
最近更新 更多