実現したいこと
以下のサイトを参考にしてSpring SecurityでCSRFトークンを利用するREST APIの作成を行っています。
https://volkruss.com/posts/p3398/
Angularで作成した画面からGET送信を行うとクッキーにCSRFトークンが格納されるようにしたいです。
前提
REST APIをSpringで作成し、
Angularで作成した画面(コンポーネント)からAPIの呼び出しを行っています。
発生している問題・エラーメッセージ
PostmanからGET送信をするとクッキーにCSRFトークンが設定されていることが確認できるのですが、
Angularで作成した画面のボタンからGET送信をしてもクッキーにCSRFトークンが設定されません。
Postmanでは正常にCSRFトークンが取得できていることからAngular側で何か設定が必要なのではないかと考えてます。
原因と対処法がありましたらご教示いただきたいです。
・PostmanでGET送信
・Angularで作成した画面からGET通信してもクッキーにCSRFトークンが設定されない
<補足>
GET通信ではCSRFトークンが設定されませんが、
POST通信を行うとCSRFトークンが設定されます。
そのため、参考サイトではGET通信→POST通信で403エラーが発生せずに通信ができていますが、
私の環境ではGET通信→POST通信(403エラー)→POST通信(200)となります。
該当のソースコード
SecurityConfig.java
1import java.util.Arrays; 2 3import org.springframework.context.annotation.Bean; 4import org.springframework.context.annotation.Configuration; 5import org.springframework.security.config.annotation.web.builders.HttpSecurity; 6import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 7import org.springframework.security.web.SecurityFilterChain; 8import org.springframework.security.web.csrf.CookieCsrfTokenRepository; 9import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler; 10import org.springframework.web.cors.CorsConfiguration; 11import org.springframework.web.cors.CorsConfigurationSource; 12import org.springframework.web.cors.UrlBasedCorsConfigurationSource; 13 14@Configuration 15@EnableWebSecurity 16public class SecurityConfig { 17 @Bean 18 public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { 19 20 http.cors(cors -> cors.configurationSource(corsConfigurationSource())); 21 22 http.csrf((csrf) -> csrf 23 .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) 24 .csrfTokenRequestHandler(new CsrfTokenRequestAttributeHandler())); 25 26 http.authorizeHttpRequests(authorize -> { 27 authorize.requestMatchers("/**").permitAll(); 28 }); 29 30 return http.build(); 31 } 32 33 //CORSの設定 34 @Bean 35 public CorsConfigurationSource corsConfigurationSource() { 36 CorsConfiguration cors = new CorsConfiguration(); 37 cors.setAllowedOrigins(Arrays.asList("http://localhost:4200")); 38 cors.setAllowedMethods(Arrays.asList("GET","POST","OPTIONS")); 39 cors.setAllowedHeaders(Arrays.asList("*")); 40 cors.setAllowCredentials(true); 41 cors.addExposedHeader("X-AUTH-TOKEN"); 42 UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); 43 source.registerCorsConfiguration("/**",cors); 44 return source; 45 } 46}
testController.java
1import org.springframework.security.core.Authentication; 2import org.springframework.security.core.context.SecurityContextHolder; 3import org.springframework.web.bind.annotation.GetMapping; 4import org.springframework.web.bind.annotation.PostMapping; 5import org.springframework.web.bind.annotation.RestController; 6 7@RestController 8public class testController { 9 10 @GetMapping("/get") 11 public String doGet() { 12 System.out.println("GET"); 13 Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 14 System.out.println(authentication); 15 return "sample GET is done"; 16 } 17 18 @PostMapping("/post") 19 public String doPost() { 20 System.out.println("POST"); 21 Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 22 System.out.println(authentication); 23 return "sample POST is done"; 24 } 25 26} 27
html
1 <button id="get" (click)="doget()">GET</button>2 <button id="post" (click)="dopost()">POST</button>3 ...
component.ts
1import { Component } from '@angular/core'; 2import { DashboardService } from './dashboard.service' 3import { HttpClientModule } from '@angular/common/http'; 4 5@Component({ 6 selector: 'app-dashboard', 7 standalone: true, 8 imports: [HttpClientModule], 9 templateUrl: './dashboard.component.html', 10 styleUrl: './dashboard.component.css' 11}) 12export class DashboardComponent { 13 message: string; 14 15 constructor(private dashboardService: DashboardService,) { 16 this.message = 'This is a sample of Angular application.'; 17 } 18 19doget(){ 20 21 fetch('http://localhost:8080/get', 22 { 23 method:'GET', 24 credentials: 'include' 25 }) 26 .then(res => res.text()) 27 .then(str =>console.log(str)) 28} 29 30 31dopost(){ 32 const csrfToken = document.cookie.replace(/(?:(?:^|.*;\s*)XSRF-TOKEN\s*\=\s*([^;]*).*$)|^.*$/, '$1'); 33 console.log(csrfToken); 34 fetch('http://localhost:8080/post',{ 35 method:'POST', 36 credentials: 'include', 37 headers: { 38 'X-XSRF-TOKEN' : csrfToken 39 }, 40 }) 41 .then(res => res.text()) 42 .then(str => console.log(str)) 43} 44}~~打ち消し線~~
補足情報(FW/ツールのバージョンなど)
spring-boot-starter-parent:3.2.4
Spring Security Version: 6.2.3
Eclipse IDE for Java Developers Version: 2023-12 (4.30.0)
Postman for Windows:10.24.7
0 コメント