ログインフォームを作成する
※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;
}
}