[リサーチ・メモ] spring-secueiryとVueを使用してログイン画面を作成する#1インメモリでログイン確認まで

## ログインフォームを作成する
※v-formに@submit.preventを記載しなければGETでリクエストされてしまう
　ヘッダーは「application/x-www-form-urlencoded」を指定しなければログインできない
```
<template>
    <v-container>
        <v-row justify="center">
            <v-col cols="12" md="6">
                <v-card class="rounded-lg py-5 px-3">
                    <v-card-title class="text-center" style="font-size: 24px;">
                        ログイン
                    </v-card-title>
                    <v-card-text>
                        <v-form @submit.prevent="login">
                            <v-text-field v-model="memberInfo.email" :rules="rules.emailRules" label="Email"
                                required></v-text-field>

                            <v-text-field v-model="memberInfo.password" :rules="rules.passwordRules" label="パスワード"
                                required></v-text-field>
                            <v-row class="d-flex justify-center align-center" style="height: 100%;">
                                <v-col cols="auto" class="text-center mx-2">
                                    <BackButton />
                                </v-col>
                                <v-col cols="auto" class="text-center mx-2">
                                    <BaseButton type="submit" to="" label="ログイン" />
                                </v-col>
                            </v-row>
                        </v-form>
                    </v-card-text>
                </v-card>
            </v-col>
        </v-row>
    </v-container>
</template>

import等

const login = async () => {
    try {
        const response = await axios.post(BASE_URL + '/login', {
            username: memberInfo.email,
            password: memberInfo.password,
        }, {
            headers: {
                'Content-type': 'application/x-www-form-urlencoded'
            }
        });
        if (response.status === 200) {
            console.log("Login success:", response);
        }
    } catch (error) {
        console.error("Login failed:", error);
    }
}
```

## SecurityConfigクラスを作成する
configureメソッドにインメモリでログインするユーザーを設定する
securityFilterChainメソッド内に認証条件を記載する
※loginProcessingUrlと似たloginPageはログイン画面を表示する為に使用される
corsConfigurationSourceメソッドはCORSエラー回避の為、フロントエンドのポートを指定する
```
@Configuration
@EnableWebSecurity
public class SecurityConfig {

	@Autowired
	public BCryptPasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}

	@Autowired
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.inMemoryAuthentication().passwordEncoder(passwordEncoder()).withUser("user")
				.password(passwordEncoder().encode("test")).roles("USER");
	}

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		http.cors(withDefaults()).csrf(csrf -> csrf.ignoringRequestMatchers(new AntPathRequestMatcher("/login"), // csrfを無視
				new AntPathRequestMatcher("/h2-console/**")))
				.headers(headers -> headers.frameOptions(frameOptions -> frameOptions.sameOrigin()))
				.authorizeHttpRequests(authorizeRequests -> authorizeRequests
						.requestMatchers(new AntPathRequestMatcher("/h2-console/**")).permitAll() // h2コンソールへのアクセスを許可
						.requestMatchers(new AntPathRequestMatcher("/login")).permitAll().anyRequest().authenticated()) //ログイン画面へのアクセスを許可
				.formLogin(form -> form.loginProcessingUrl("/login").failureHandler((request, response, exception) -> {
					response.setStatus(HttpStatus.UNAUTHORIZED.value()); // ログイン失敗時に401を返すように設定
				}));

		return http.build();
	}

	@Bean
	CorsConfigurationSource corsConfigurationSource() {
		CorsConfiguration configuration = new CorsConfiguration();
		configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000")); // フロントエンドのオリジンを許可
		configuration.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS"));
		configuration.setAllowedHeaders(Arrays.asList("*"));
		configuration.setAllowCredentials(true);

		UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
		source.registerCorsConfiguration("/**", configuration);

		return source;
	}
}
```