Help us understand the problem. What is going on with this article?

Spring SecurityでDB認証&BCryptでハッシュ化

概要

  • Spring Securityで必要最低限のログイン機能を実装する。(権限周りは触れません。)
  • ログインフォームなどはSpring Securityで用意されているものを使う。
  • 仕組みはあまり理解できていないので、また別でまとめます。
  • この投稿はとりあえず、動くようになったというところまで!

開発環境

  • OS:Windows10
  • IDE:eclipse 2019-12
  • Java:13
  • Spring boot:2.2.5(Gradle)
  • DB:Oracle 12c

Spring Securityの導入

依存関係で下記の4つを選択

  • Spring Security
  • Spring Web
  • Spring Data JPA
  • Oracle Driver ←使用するDBのDriverを選択してください 2020-03-15-14-06-34.png


DB接続情報をプロパティファイルに記述

  • それぞれのDBに合った内容にしてください。
application.properties
spring.datasource.url=jdbc:oracle:thin:@//localhost:1521/[データベース名]
spring.datasource.username=[DBユーザー名]
spring.datasource.password=[パスワード]
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver


ユーザー情報のテーブルを作成

create table USER_TABLE (
    USER_ID VARCHAR2(30 char)
  , FAMILY_NAME VARCHAR2(10 char) not null
  , FIRST_NAME VARCHAR2(10 char) not null
  , PASSWORD VARCHAR2(255) not null
  , constraint USER_TABLE_PKC primary key (USER_ID)
) ;


データ登録

下記のパスワードは「pass」をハッシュ化したものです。
この記事を参考にしました。

INSERT INTO
    USER_TABLE
VALUES(
    '0001'
   ,'テスト'
   ,'太郎'
   ,'$2a$10$w0C4tFU.SLFATC1Y6Y4uy.vMYsLXhlfvgnFP4dLbRjEa6/Ag1csKS'
   );


Entityクラスを作成

UserTable.java
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "USER_TABLE")
public class UserTable {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "USER_ID")
    private String userId;

    @Column(name = "FAMILY_NAME")
    private String familyName;

    @Column(name = "FIRST_NAME")
    private String firstName;

    @Column(name = "PASSWORD")
    private String password;

// Getter,Setterは省略


リポジトリを作成

UserTableRepository.java
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.azkz.entity.UserTable;

@Repository
public interface UserTableRepository extends JpaRepository<UserTable, String> {

    public UserTable findByUserId(String userId);

}


SecurityConfigを作成

DemoSecurityConfig.java
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@EnableWebSecurity
public class DemoSecurityConfig extends WebSecurityConfigurerAdapter {

    //アクセス可能なURLの制限とログイン成功時の遷移先の指定をするメソッド
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.authorizeRequests()
                .mvcMatchers("/").permitAll() // 「/」は誰でもアクセスできる
                .anyRequest().authenticated() // それ以外はログインが必要
                .and()
                .formLogin()
                .defaultSuccessUrl("/success"); // ログイン成功時には「/success」にGetリクエストをする
    }

    //入力されたパスワードをBCrypt方式でハッシュ化するメソッド
    @Bean
    protected PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}


UserDetailsServiceを作成

  • DBからユーザ情報を取得し、DemoUserDetailsをインスタンス化する。
DemoUserDetailsService.java
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.azkz.entity.UserTable;
import com.azkz.repository.UserTableRepository;

@Service
public class DemoUserDetailsService implements UserDetailsService {

    @Autowired
    UserTableRepository userTableRepository;

    @Override
    public UserDetails loadUserByUsername(String userId) throws UsernameNotFoundException {

        //入力されたUserIDを条件にDBからデータを取得する
        UserTable userTable = userTableRepository.findByUserId(userId);

        // 入力値(ユーザーID、パスワード)とインスタンス化したDemoUserDetailsクラスを
        // SpringSecurityの内部で比較することで、ログインチェックを行っている。
        return new DemoUserDetails(userTable);

    }

}


UserDetailsを作成

  • このクラスが入力情報(ユーザID、パスワード)と比較されることになる(?)
  • ログイン後のセッション情報もこれ
DemoUserDetails.java
import java.util.Collections;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;

import com.azkz.entity.UserTable;

public class DemoUserDetails extends User {

    @Autowired
    UserTable userTable;

    public DemoUserDetails(UserTable userTable) {
        // 「Collections.emptySet()」は本来は権限名のコレクションとなる。今回は空。
        super(userTable.getUserId(), userTable.getPassword(),Collections.emptySet());
        this.userTable = userTable;
    }

    // セッション情報から独自の項目を取得するためのGetter

    public String getFirstName() {
        return this.userTable.getFirstName();
    }

    public String getFamilyName() {
        return this.userTable.getFamilyName();
    }

}


Controllerを作成

  • 成功時にログインユーザの情報を表示する
DemoController.java
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import com.azkz.security.DemoUserDetails;

@RestController
public class DemoController {

    @GetMapping("/success")
    public DemoUserDetails loginSuccess() {
        // ログイン中のユーザ情報を取得
        DemoUserDetails demoUserDetails =
                (DemoUserDetails) SecurityContextHolder
                                    .getContext().getAuthentication().getPrincipal();

        return demoUserDetails;
    }
}


画面確認

http://localhost:8080/login にアクセス

2020-03-15-19-24-53.png


ログイン成功

2020-03-15-19-26-25.png


ログイン失敗

2020-03-15-19-28-26.png


終わりに

  • 表面的なことしか書いておりませんが、間違い・不足点等がございましたら、ぜひご教示いただきたく存じます。何卒!
1412azkz
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away