概要
- https://qiita.com/Yoshihiro-Hirose/items/744c8bff3c3720013946 の続き
- Spring Security を適用し、認証情報にデータベースを使用する。
- パスワードも平文で保存しないようにする
手順
-
ビルドスクリプトに Spring Security と JPA を追加
build.gradleimplementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-security'
-
以下のconfigクラスを新規作成
package com.example.demo.config; import org.springframework.context.annotation.Bean; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; @EnableWebSecurity public class SecurityConfig2 { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.authorizeRequests() .anyRequest().authenticated() .and() .formLogin() .defaultSuccessUrl("/success"); return http.build(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
-
認証情報を持つテーブルに対応したエンティティクラスを用意
@Entity @Table(name = "account") public class Account { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id") private int id; @Column(name = "user_name") private String userName; @Column(name = "password") private String password; // setter, getter 省略 }
-
- を取得する Repository クラスを定義
@Repository public interface AccountRepository extends JpaRepository<Account, Integer> { Account findByUserName(String userName); }
-
認証に使うユーザ情報を取得するサービスを定義
package com.example.demo.security; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import java.util.Collections; @Service public class AccountUserDetailsService implements UserDetailsService { private final AccountRepository accountRepository; @Autowired public AccountUserDetailsService(AccountRepository accountRepository) { this.accountRepository = accountRepository; } @Override public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException { Account account = accountRepository.findByUserName(userName); return new User(account.getUserName(), account.getPassword(), Collections.emptyList()); } }
-
テストクラスなどでハッシュ化したパスワードを取得
@SpringBootTest public class PasswordTest { @Autowired private PasswordEncoder encoder; @Test public void encode() { System.out.println(encoder.encode("pass")); System.out.println(encoder.encode("password")); } }
実行結果例$2a$10$T7dckfpU4EC0nKxEKKYukeTa1ZXGBtKc5ZrEFfVNZ/CGoYmUDRE3e $2a$10$hCZ9AJeq20LpMk.wRHJf0eUdHABHatUp2Tnb8uqe8J3/ZuJ4njun.
-
ハッシュ化したパスワードを使ってデータベースに登録
- H2 を使った例
schema.sql
CREATE TABLE IF NOT EXISTS account ( id INTEGER NOT NULL AUTO_INCREMENT, user_name VARCHAR(128) NOT NULL, password VARCHAR(512) NOT NULL, PRIMARY KEY (id) );
data.sqlINSERT INTO account (user_name, password) VALUES('user1', '$2a$10$T7dckfpU4EC0nKxEKKYukeTa1ZXGBtKc5ZrEFfVNZ/CGoYmUDRE3e'); INSERT INTO account (user_name, password) VALUES('user2', '$2a$10$hCZ9AJeq20LpMk.wRHJf0eUdHABHatUp2Tnb8uqe8J3/ZuJ4njun.');
- アプリケーションを起動して、適当なページにアクセスする
- ログインページが表示されるので、
user1
pass
などで認証する