public class CsrfTokenLogger implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
CsrfToken o = (CsrfToken) servletRequest.getAttribute("_csrf");
filterChain.doFilter(servletRequest, servletResponse);
}
}
@Configuration
public class ProjectConfig {
...
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.addFilterAfter(new CsrfTokenLogger(), CsrfFilter.class)
.authorizeHttpRequests(auth -> auth.anyRequest().permitAll());
return http.build();
}
}
@Configuration
public class ProjectConfig {
...
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf(c -> {
c.ignoringRequestMatchers("/ciao");
RegexRequestMatcher matcher = new RegexRequestMatcher(".*[0-9].*", HttpMethod.POST.name());
c.ignoringRequestMatchers(matcher);
})
.authorizeHttpRequests(auth -> auth.anyRequest().permitAll());
return http.build();
}
}
@Entity
public class Token {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String identifier;
private String token;
public void setToken(String token) {
this.token = token;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
public String getToken() {
return this.token;
}
}
public interface JpaTokenRepository extends JpaRepository<Token, Long> {
Optional<Token> findByIdentifier(String identifier);
}
public class CustomCsrfTokenRepository implements CsrfTokenRepository {
private final JpaTokenRepository jpaTokenRepository;
public CustomCsrfTokenRepository(JpaTokenRepository jpaTokenRepository) {
this.jpaTokenRepository = jpaTokenRepository;
}
@Override
public CsrfToken generateToken(HttpServletRequest request) {
String uuid = UUID.randomUUID().toString();
return new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", uuid);
}
@Override
public void saveToken(CsrfToken csrfToken, HttpServletRequest request, HttpServletResponse response) {
// 클라이언트 ID로 데이터베이스에서 토큰을 얻는다.
String identifier = request.getHeader("X-IDENTIFIER");
Optional<Token> existingToken = jpaTokenRepository.findByIdentifier(identifier);
// ID가 존재하면 새로 생성된 값으로 토큰 값을 업데이트 한다.
if (existingToken.isPresent()) {
Token token = existingToken.get();
token.setToken(csrfToken.getToken());
} else {
// 존재하지 않으면 생성한 CSRF 토큰과 ID로 새 데이터를 생성한다.
Token token = new Token();
token.setToken(csrfToken.getToken());
token.setIdentifier(identifier);
jpaTokenRepository.save(token);
}
}
@Override
public CsrfToken loadToken(HttpServletRequest request) {
String identifier = request.getHeader("X-IDENTIFIER");
Optional<Token> existingToken = jpaTokenRepository.findByIdentifier(identifier);
if (existingToken.isPresent()) {
Token token = existingToken.get();
return new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", token.getToken());
}
return null;
}
}
@Configuration
public class ProjectConfig {
...
@Bean
public CsrfTokenRepository customCsrfTokenRepository() {
return new CustomCsrfTokenRepository();
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http, CustomCsrfTokenRepository customCsrfTokenRepository) throws Exception {
http.csrf(c -> {
c.csrfTokenRepository(customCsrfTokenRepository());
c.ignoringRequestMatchers("/ciao");
})
.authorizeHttpRequests(auth -> auth.anyRequest().permitAll());
return http.build();
}
}
@Controller
public class MainPageController {
@Autowired
private ProductService productService;
@GetMapping("/main")
@CrossOrigin("http://localhost:8080")
public String main(Authentication a, Model model) {
model.addAttribute("username", a.getName());
model.addAttribute("products", productService.findAll());
return "main.html";
}
}
@Configuration
public class ProjectConfig {
...
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http, CustomCsrfTokenRepository customCsrfTokenRepository) throws Exception {
http.cors(c -> {
CorsConfigurationSource source = request -> {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(List.of());
config.setAllowedMethods(List.of());
return config;
};
c.configurationSource(source);
});
...
return http.build();
}
}