はじめてのSpringBoot4 ~ログイン機能:DB値利用~
はじめに
はじめまして
私はJavaを研修で少しかじった程度でSpringBootを使用した開発に参加し、てんやわんやしております森田和華です。
全く分からない中から少しずつ調べて実装をしていますが、自分の学習の為にも記事にして残しておこうと思い作成しております。
参考にしていただける際はそのあたりを念頭に置いたうえで参考にしていただければと思います。
もし私の記事を読んでおかしなところなどありましたらご指摘いただけると嬉しいです。
前回までの記事はこちらです。
はじめてのSpringBoot1 ~プロジェクトの作成~
はじめてのSpringBoot2 ~DB接続~
はじめてのSpringBoot3 ~ログイン機能その1~
環境
SpringBootバージョン:2.4.0
Javaバージョン:8
DB:MySQL 8.0
IDE:eclipse
ログイン処理にDBのデータを利用する
前回はデフォルトのログイン機能を実装しましたが、ユーザー名とパスワードがデフォルト指定のままで変更出来ていなかったのでDBを利用した実装に変更していきます。
UserDetailsの実装
まず認証処理で必要となる資格情報(ユーザー名とパスワード)とユーザーの情報を提供するためのインターフェースのUserDetailsの実装クラスを作成する必要があります。
今回の私の実装ではuser_sampleテーブルのエンティティで実装を兼ねることにします。
package com.elpmas.test.domain.entity;
import java.util.Collection;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import lombok.Getter;
import lombok.Setter;
//ユーザー情報Entity
@Entity //エンティティクラスのアノテーション
@Getter //Getterの自動生成のアノテーション
@Setter //Setterの自動生成のアノテーション
@Table(name="user_sample") //テーブル名の指定
public class User implements UserDetails{
@Id //idであることをアノテーションで明示する
@Column(name="id") //DB上のカラム名を指定する
private int id;
@Column(name="username")
private String username;
@Column(name="password")
private String password;
@Column(name="delflg")
private int delflg;
//この下はインターフェースのメソッドを実装する
//ユーザーに与えられる権限リストを返却するメソッド
@Override
public Collection<? extends GrantedAuthority> getAuthorities(){
return null;
}
//ユーザー名を返却するメソッド
@Override
public String getUsername() {
return this.username;
}
//パスワードを返却するメソッド
@Override
public String getPassword() {
return this.password;
}
//アカウントの有効期限の状態を判定するメソッド
@Override
public boolean isAccountNonExpired() {
return true;
}
//アカウントのロック状態を判定するメソッド
@Override
public boolean isAccountNonLocked() {
return true;
}
//資格情報の有効期限の状態を判定するメソッド
@Override
public boolean isCredentialsNonExpired() {
return true;
}
//有効なユーザーか判定するメソッド
@Override
public boolean isEnabled() {
return true;
}
}
UserDetailsServiceの実装
UserDetailsServiceは資格情報とユーザーの状態をデータストアから取得するためのインターフェースです。
今回はこちらの実装も必要です。
package com.elpmas.test.service;
import org.springframework.beans.factory.annotation.Autowired;
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 com.elpmas.test.domain.entity.User;
import com.elpmas.test.domain.repository.UserRepository;
@Service
public class UserDetailsServiceImpl implements UserDetailsService{
//ユーザーテーブルの取得用repositoryのインスタンス生成
@Autowired //オートワイヤリング設定(DIコンテナから型が一致するものを取り出しインジェクションする)
private UserRepository userRepository;
//与えられたユーザー名を用いてUserDetailsを取得し返却するメソッド
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//データベースからアカウント情報を検索する
User user = userRepository.findByUsernameEquals(username);
return user;
}
}
認証処理の適用
また作成したUserDetailsServiceを使用して認証処理を行うにはDaoAuthenticationProviderを有効化して作成したUserDetailsServiceを適用する必要があります。
以前のWebSecurityConfigに追記していきます。
package com.elpmas.test.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import com.elpmas.test.domain.service.UserDetailsServiceImpl;
/**
* SpringSecurityを利用するための設定クラス
* ログイン処理でのパラメータ、画面遷移や認証処理でのデータアクセス先を設定する
*/
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//UserDetailsServiceを利用出来るように@Autowiredしておく
@Autowired
private UserDetailsServiceImpl userDetailsService;
//認証用パスワードはハッシュ化して扱うためPasswordをハッシュ化する際に必要なBCryptPasswordEncoder()を返すメソッドを作成しておく。
@Bean
public PasswordEncoder passwordEncoder() {
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
//これはハッシュ化済みの値をDBに登録する確認用に出力させるコード//
String password = "1234";
String digest = bCryptPasswordEncoder.encode(password);
System.out.println("ハッシュ値 = " + digest);
///////////////////////////////////////////////////////////////
return new BCryptPasswordEncoder();
}
/**
* 認可設定を無視するリクエストを設定
* 静的リソース(image,javascript,css)を認可処理の対象から除外する
*/
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/resources/**");
}
/**
* 認証・認可の情報を設定する
* SpringSecurityのconfigureメソッドをオーバーライドしています。
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated();
http
.formLogin()
.defaultSuccessUrl("/sample", true);
}
/**
* 認証時に利用するデータソースを定義する設定メソッド
* ここではDBから取得したユーザ情報をuserDetailsServiceへセットすることで認証時の比較情報としている
*/
@Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception{
//UserDetailsServiceを設定してDaoAuthenticationProviderを有効化する
auth.userDetailsService(userDetailsService).
//上記作成のエンコードを設定しハッシュ化する
passwordEncoder(passwordEncoder());
}
}
動作確認
ここまで準備出来たら起動してみて動作確認をしていきます。
起動すると変わらずログイン画面が表示されます。
そしてここでDBに登録するはずのパスワード候補の「1234」のハッシュ化後の数値が表示されているか確認します。(確認してDBへの登録が済みましたらこの部分のコードは消してしまっていいと思います。)
コンソール画面を確認すると、出てました。
ではこの文字列を使ってDBのレコードを準備していきます。
レコードの準備が出来ましたらログイン画面にもどって今登録したユーザー名とパスワードを入力します。
無事ログインに成功しました!
ログインに失敗するとこちらの画面に遷移します。
エラーメッセージも出してくれていますが今回のメッセージは英語ですね。
次回
無事にDBの内容をログインに使用することが出来ました!
今回まではSpringSecurityでデフォルトで用意されているログイン画面を使いましたが実務ではログイン画面は自作することが多いと思います。
ですので、次回はログイン画面のカスタマイズをしていきたいなと思います。
参考文献
Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発 (著 株式会社NTTデータ)
Discussion
UserRepositoryクラスが載ってませんよ