【Spring Security】データベースを利用したログイン画面を実装してみる

spring boot

前回では、Spring Securityがデフォルトで提供しているログイン画面を作ってみました。
今回はDBを利用したログイン画面を実装してみます。

環境:Mac

ログイン情報保存するaccountsテーブルDDL

CREATE TABLE `accounts` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL,
  `password` varchar(100) NOT NULL,
  `role` varchar(50) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

UserテーブルのEntityクラス

package com.example.model;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Data;

@Entity
@Table(name = "accounts")
@Data
public class Account {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, unique = true)
    private String username;

    @Column(nullable = false)
    private String password;

    @Column(nullable = false)
    private String role;

}

ログイン用コントローラクラス

@Controller
public class LoginController {

    @GetMapping("/login")
    public String login() {
        return "login";
    }
}

認証情報取得クラス

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Account account = userRepository.findByUsername(username).orElseThrow(() -> new UsernameNotFoundException("User not found"));
        return new User(account.getUsername(), account.getPassword(), new ArrayList<>());
    }
}

loadUserByUsername メソッドの役割

このメソッドは、ユーザー名を引数に取り、UserDetails オブジェクトを返します。UserDetails オブジェクトには、ユーザーのユーザー名、パスワード、およびユーザーの権限(ロール)が含まれます。Spring Security はこの情報を使用して、ユーザーの認証と認可を行います。

ログイン画面HTML(一部抜粋)

<div class="login-container">
	    <form th:action="@{/login}" method="post">
	        <div>
	            <label for="username">Username:</label>
	            <input type="text" id="username" value="user" name="username" required />
	        </div>
	        <div>
	            <label for="password">Password:</label>
	            <input type="password" id="password" value="tsd5652" name="password" required />
	        </div>
	        <div>
	            <button type="submit">Login</button>
	        </div>
	    </form>
</div>

ユーザ名、パスワードのInputタグのname属性の値は、デフォルト値の”username”, “password”とする。

SecurityConfigクラス

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(authorizeRequests -> authorizeRequests
                .requestMatchers("/account/register").permitAll()  // 登録ページ
                .anyRequest().authenticated()  // その他のリクエストは認証を要求
            )
            .formLogin(formLogin -> formLogin
                .loginPage("/login")  // カスタムログインページを指定
                .defaultSuccessUrl("/", true)  // ログイン成功後にルートパスにリダイレクト
                .permitAll()
            )
            .logout(logout -> logout
                .permitAll()
            )
            .csrf(csrf -> csrf.disable());  // CSRF保護を無効化する

        return http.build();
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
タイトルとURLをコピーしました