前回では、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();
}
}