Spring Securityでのログイン認証機能
はじめに
この記事は、Spring Securityを使用したログイン認証機能の導入について記載しております。
実際に、システムに実装する際に、参考記事を調べてもバージョン違いやMavenのものが多く、メソッドの理解と導入手順に苦戦をしたので、備忘録として書き留めます。
基本的には公式のリファレンスを参考にしております。
追記(2023.07.21):
現在、バージョンが変わりこちらの方法も非推奨になってしまっているので、
最新の記載方法を学習次第、書き直したいと思います。
開発環境
・JDK17
・Spring Tool Suite4
・Spring Boot 3.1.1
・Spring Security
前提
今回は既にWebアプリケーションを作成できていることが前提での手順です。
想定するプロジェクト詳細は、通販ECサイト。
それぞれのページとURLについては以下の通りで、コードは割愛します。
・トップページ ( / )
・新規会員登録ページ ( /registerMember )
・ログインページ( /loginMember )
・商品一覧ページ ( /showList )
・商品詳細ページ ( /showDetail )
・ショッピングカートページ ( /shoppingCart )
・注文画面 ( /order )
・注文履歴画面 ( /orderHistory )
今回は、ピンク文字の画面はログイン状態にないと遷移できないという設定で進めていきます。
実装手順
① build.gradleにSpring Securityを追加する
② SecurityConfigクラスを作成する (com.example.commonパッケージに格納)
③ LoginUserクラスを作成する (com.example.domainパッケージに格納)
①<build.gradle>にSpring Securityを追加する (今回はテスト用は追加してません)
plugins {
id 'java'
id 'org.springframework.boot' version '3.1.1'
id 'io.spring.dependency-management' version '1.1.0'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-web'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'org.postgresql:postgresql'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
//以下、SpringSecurity使用のため追加が必要
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
}
tasks.named('test') {
useJUnitPlatform()
}
ちなみに元々「Spring Stater Project」でプロジェクトを新規作成する際に
最初から依存関係として設定済みのものは
・Thymeleaf
・Validation
・Spring Web
・Spring Boot DevTools
・PostgreSQL Driver
になります。
②SecurityConfigクラスを作成する
「SeciurityConfig」クラスは、SpringSecurityに関する設定を行うクラス。
「セキュリティ設定の無効化」「ログイン認証に関する認可や遷移ページなどの設定」「ハッシュ化を行う実装オブジェクトの作成」などを設定します。
package com.example.common;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@Configuration
public class SecurityConfig {
/**
* 特定のリクエストに対して「セキュリティ設定」を無視する設定など全体にかかわる設定ができる.
* 具体的には静的リソースに対してセキュリティの設定を無効にする。
* (無効化にしないとデザイン部分を表示するにも認証が必要になってしまうため)
*/
@Bean
WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().requestMatchers("/css/**", "/img/**", "/js/**");
}
/**
* 個々の認可の設定や「ログイン」「ログアウト」についての設定を行う.
*/
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// 認可に関する設定
http.authorizeHttpRequests()
.requestMatchers("/", "/showList", "/showDetail", "/shoppingCart/addItem", "/shoppingCart/showCartList", "/shoppingCart/deleteItem", "/registerMember", "/registerMember/register", "/login").permitAll()
.anyRequest().authenticated();
// ログインに関する設定
http.formLogin().loginPage("/loginMember").loginProcessingUrl("/loginMember/login")
.failureUrl("/loginMember?error=true")
.defaultSuccessUrl("/showList",false)
.usernameParameter("email").passwordParameter("password");
// ログアウトに関する設定
http.logout().logoutRequestMatcher(new AntPathRequestMatcher("/loginMember/logout"))
.logoutSuccessUrl("/")
.deleteCookies("JSESSIONID").invalidateHttpSession(true);
return http.build();
}
/**
* アルゴリズムのハッシュ化する実装を行うメソッド.
*
* @return bcryptアルゴリズムでハッシュ化する実装オブジェクト
*/
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
SecurityFilterChain securityFilterChain(HttpSecurity http)メソッドについて、
詳しく個々で何を設定しているかというと、
http.authorizeHttpRequests() : 認可に関する設定
.requestMatchers() : ログイン認証前でもアクセスしたいパスを記載する
※注意点として、画面表示のパスだけでなく、紐づく処理を行うパスも記載する
.permitAll() : 認証なしでアクセスを許可する
.anyRequest().authenticated() : それ以外のパスは認証が必要
http.formLogin() : ログインに関する設定
.loginPage() : ログイン画面に設定したい画面のパスを記載する
.loginProcessingUrl() : ログインボタンを押した時に遷移させるパス(ログイン処理を行うパス)
.failureUrl() : ログインに失敗した際に遷移させるパス(エラーページに遷移)
.defaultSuccessUrl() : 第1引数にはデフォルトでログイン成功時に遷移させたい画面のパスを記載
第2引数には、true (認証後、常に第1引数のパスに遷移) もしくは
false (認証されず再度ログイン画面に飛ばされてもログインができたら
第1引数のパスに遷移する)を記載する
.usernameParameter() : 認証時に使用するユーザー名のリクエストパラメータ名
(ログイン時に入力する項目※今回はメールアドレス)
.passwordParameter() : 認証時に使用するパスワードのリクエストパラメータ名
http.logout() : ログアウトに関する設定
.logoutRequestMatcher() : ログアウトボタンを押した時に遷移させるパスを記載する
(ログアウト処理を行うパス)
.logoutSuccessUrl() : ログアウト後に遷移させたい画面のパスを記載する
.deleteCookies() : ログアウト後、Cookieに保存されているセッションIDを削除する
.invalidateHttpSession() : true (ログアウト後、セッションを無効にする) か
false (ログアウト後、セッションを無効にしない)かを記載する
となります。(個人的な認識なので、間違っているところがあったらすみません。)
また、今回クラスに@EnableWebSecurityを記載していないのですが、
こちらのプロジェクトはSpringBootを使用しており、
@SpringBootApplicationが実行用クラスに存在しているため省略しています。
(@SpringBootApplication に @EnableWebSecurity が含まれているため)
③LoginUserクラスを作成する
DBに格納する会員情報とは別に、SpringSecurityでのログイン認証で使用する時には
権限が必要なため会員情報に権限を付与しています。
package com.example.domain;
import java.util.Collection;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.GrantedAuthority;
public class LoginUser extends User{
/** 会員情報(ログインに使用する) */
private final Member member;
/**
* 通常の会員情報に加え、認可用ロールを設定する.
*
* @param member 会員情報
* @param authorityList 権限情報が入ったリスト
*/
public LoginUser(Member member, Collection<GrantedAuthority> authorityList) {
super(member.getEmail(), member.getPassword(), authorityList);
this.member = member;
}
/**
* 会員情報を返す.
*
* @return 会員情報
*/
public Member getMember() {
return member;
}
}
以上となります。今回、私が実装したのは通販サイトのログイン機能にSpring Securityのログイン認証を用いるケースだったので、シンプルにログイン機能だけの搭載の学習となると足りないコードなどが出てくるかもしれません。
(知らぬ間に依存関係に助けられているものもあるかもしれないので...)
これからもこのように戸惑ったものに関しては、ブログに書き留めていこうと思います。
日々、学習頑張ります。