我有一个基于spring boot,spring-security,thymeleaf的网站,在某些情况下,我还使用ajax。
问题:
我在Spring Security中使用表单登录安全性。在浏览器中,登录后我可以使用rest API(GET),但是使用 ajax ,即使我的ajax请求在cookie中包含会话ID,它也会返回 403 。
安全配置:
@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]不起作用。
答案 0 :(得分:0)
感谢大家
我通过禁用CSRF来解决了这个问题,我添加了
.csrf()。disable()。cors()
在我的春季安全配置中:
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回答了一个有用的解释……感谢他
答案 1 :(得分:0)
为什么.csrf().disable().cors()
起作用了?
CSRF 代表跨站点请求伪造
简单来说,它是一种与请求一起发送以防止攻击的令牌。为了使用Spring Security CSRF保护,我们首先需要确保对修改状态的任何内容使用正确的HTTP方法(PATCH
,POST
,PUT
和DELETE
–不是GET
)。
某些框架通过使用户会话无效来处理无效的CSRF令牌,但这会导致其自身的问题。相反,默认情况下,Spring Security的CSRF保护会产生 HTTP 403访问被拒绝。
如果使用的是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);
});