1
5

More than 1 year has passed since last update.

Spring Security その2〜DB認証

Posted at

前回の記事でログイン機能の作成を実施しましたが、ログインユーザは「User」で固定。パスワードはコンソールに出力と、実際の運用には程遠い内容。

今回はDBに登録されたユーザ名(ID)と、パスワードを照合していきます。

テーブルの準備

今回使用するテーブルはこちら
spring securityの学習がメインなので詳細は割愛しますが、account-idはcharacterにすればよかった。
account_lock〜account_groupまでは今回は使用しませんが、いずれこの辺も使用する予定
telephone1と2はユーザID、パスワードの他に、もう1点(合計3点一致)で認証とする場合に使用する予定

image.png

テーブルにデータを追加

id:12345
password:password
で登録しておきます。
※パスワードはハッシュ化した値を格納します。
ハッシュ化はこのサイトで実施できます。
ハッシュ化についての説明はこちらの記事を読んでください

select account_id,password from user_account;

image.png

テーブルから取得した値を格納するentityを作成

package com.example.entity;
public record UserAccount(int accountId,String password) {}

テーブルからaccount_idとpasswordを取得するmapperを作成

  • Java
package com.example.mapper;

import org.apache.ibatis.annotations.Mapper;

import com.example.entity.UserAccount;

@Mapper
public interface DemoMapper {
	public UserAccount getAccount(int accountId);
}

  • xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.DemoMapper">
    <select id="getAccount" resultType="com.example.entity.UserAccount">
        SELECT
            account_id,
            password
         FROM
            user_account
         WHERE
            account_id = #{accountId}   
    </select>
</mapper>

今回のメインのひとつ UserDetailsの実装

UserDetailsインターフェースを実装します。
ポイント1:コンストラクタを作成し、UserAccountを設定します。
ポイント2:getUsernameとgetPasswordに上記で設定したUserAccountから取得した値を返すよう実装します。
その他は今回は使用しないのでis〜のメソッドは「true」を返却する。
注意:自動生成された時点ではFalseを返却するようになってます。Falseではアカウントロック状態等になってしまうので、Trueを返却するように変更します。

package com.example.auth;

import java.util.Collection;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import com.example.entity.UserAccount;

public class DemoUserDetails implements UserDetails {
	private final UserAccount user ;
	
	public DemoUserDetails(UserAccount user) {
		this.user =user;		
	}

	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		// TODO 自動生成されたメソッド・スタブ
		return null;
	}

	@Override
	public String getPassword() {
		return this.user.password();
	}

	@Override
	public String getUsername() {
		return Integer.valueOf(user.accountId()).toString();
	}

	@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の実装

ポイント1:mapperを使用し、Dbからデータを取得し、UserAccountに設定する。
※アカウントIDをintで作成してしまったため、型変換が必要。ん〜やっぱりcharacterで作成すべきだった・・・
ポイント2:取得結果が0件(ユーザが存在しない)の場合、「UsernameNotFoundException」をthrowする
ポイント3:取得したUserAccountを指定して、UserDetailsを作成する

package com.example.auth;

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.example.entity.UserAccount;
import com.example.mapper.DemoMapper;


@Service
public class DemoUserDetailsService implements UserDetailsService {

	@Autowired
	DemoMapper mapper;
	
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		UserAccount user = mapper.getAccount(Integer.valueOf(username));
		if (user == null) {
			throw new UsernameNotFoundException("not found : " + username);
		}
		return (new DemoUserDetails(user));
	}
}

最後にSecurityConfigを修正

ポイント:passwordEncoderを追加

package com.example.conf;

import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
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;

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {


    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
        .formLogin()
        .and()
        .logout()
        .and()
        .authorizeHttpRequests(authz -> authz
                .requestMatchers(PathRequest.toStaticResources().atCommonLocations())
                .permitAll()
                .anyRequest().authenticated()
        );
        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

実行してログインしてみる

http://localhost:8080/toppage にアクセスするとログイン画面が表示されるので
UserNameに12345
Passwordにpassword を入力

image.png

ログイン成功し、トップページへ遷移できました。
image.png

1
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
5