我正在 Spring Boot 中创建一个简单的项目,但在创建此 POST 请求时遇到一些困难。 基本上每次我尝试时都会出现 403 错误(有效负载是正确的,只有状态给我错误说它已关闭,因为我“没有访问权限”)。我什至尝试过 .permitAll() 但它仍然不起作用。
一些代码:
//
// I have the following js code:
//
// Creates a new event
const newEvent = {
id: null,
title: title,
start: start,
end: end,
allDay: allDay,
backgroundColor: backgroundColor,
textColor: textColor,
extendedProps: {
description: description,
creator: creator
}
};
// Sends event to backend
fetch('/api/events/add', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(newEvent)
})
.then(response => {
if (!response.ok) {
throw new Error('Error saving the event.');
}
return response.json();
})
.then(data => {
// Add the event to the calendar
newEvent.id = data.id;
gereralCalendar.addEvent(newEvent);
personalCalendar.addEvent(newEvent);
})
.catch(error => {
console.error('Error:', error);
});
//
// I also have the following Controller:
//
@RestController
@RequestMapping("/api/events")
public class EventRestController {
@Autowired
EventService eventService;
@Autowired
UserService userService;
@GetMapping("/all")
public List<EventDto> getAllEvents() {
return eventService.findAllEvents();
}
@GetMapping("/personal")
public List<EventDto> getPersonalEvents(Principal principal) {
return eventService.findEventsUser(principal.getName());
}
@PostMapping("/add")
public ResponseEntity<Event> createEvent(@RequestBody EventDto eventDto) {
Event savedEvent = eventService.saveEvent(eventDto);
return ResponseEntity.ok(savedEvent);
}
}
//
// Also this class:
//
@Getter
@Setter
public class EventDto {
private int id;
private String title;
private Boolean allDay;
private LocalDateTime start;
private LocalDateTime end;
private String backgroundColor;
private String textColor;
private ExtendedProps extendedProps;
@Getter
@Setter
public static class ExtendedProps {
private String description;
private String creator;
// Constructors
}
// Constructors
}
//
// And finally the following Spring Security configuration:
//
// I HAVE TWO ROLES -> USER and ADMIN -> hierarchy = "ROLE_ADMIN > ROLE_USER"
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) ->
authorize
.requestMatchers("/").permitAll() // nothing
.requestMatchers("/index").permitAll() // index.html
.requestMatchers("/home").hasRole("USER") // home.html
.requestMatchers("/calendar").hasRole("USER") // events_calendar.html
.requestMatchers("/register/**").hasRole("ADMIN") // register.html
.requestMatchers("/api/events/all").hasRole("USER") // GET API
.requestMatchers("/api/events/personal").hasRole("USER") // GET API
.requestMatchers("/api/events/add").hasRole("USER") // POST API
)
.formLogin(
form -> form
.loginPage("/login")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/home") // home.html
.permitAll()
)
.logout(
logout -> logout
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.permitAll()
);
return http.build();
}
我尝试修改POST js代码,也给每个人访问它的权限,但仍然不起作用。
我希望将 newEvent 发送到后端,然后将其保存在数据库中。
我成功解决了这个问题。本质上,这是因为 Spring Security 默认启用了 CSRF(跨站请求伪造)。我没有禁用它;相反,我利用 Thymeleaf 依赖项来检索令牌。
`// Dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
// Create configuration for repository of CSRF Tokens
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setSessionAttributeName("_csrf");
return repository;
}
// Add to .csrf to filterChain
.csrf(csrf -> csrf.csrfTokenRepository(csrfTokenRepository()));
// In HTML add
<meta name="_csrf" th:content="${_csrf.getToken()}" />
<meta name="_csrf_header" th:content="${_csrf.getHeaderName()}" />
// And add
const csrfToken = document.querySelector('meta[name="_csrf"]').getAttribute('content');
const csrfHeader = document.querySelector('meta[name="_csrf_header"]').getAttribute('content');
fetch('/api/events/add', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
[csrfHeader]: csrfToken // Include the CSRF token in the request header
},
body: JSON.stringify(newEvent)
})
// [...]`