テーブル認証
データベース上のユーザー情報を使用して認証処理を行う方法について説明します。
認証処理の実装には Spring Security を使用します。
以下のサンプルコードの動作確認環境については、 動作確認環境と依存ライブラリについて を参照してください。
Tip
このサンプルでは、データベースへのアクセスに Doma2 を使用しています。 Doma2を使用することで、SQLを外部ファイルで管理できるなどのメリットがあります。
認証で使用するテーブルの準備
データベースのテーブルを使って認証処理を行うため、ユーザ情報(ユーザ名やパスワード)を保持するテーブルを事前に作成します。 この例では、認証処理に最低限必要となるユーザ名とパスワードのみを保持しています。
create table users (
username varchar(255) not null,
password varchar(60) not null,
primary key (username)
);
create table user_role (
username varchar(255) not null,
role varchar(255) not null,
primary key (username, role)
);
実装例
Spring Securityの Form Login および Logout を参考に、作成したログインページを表示するように設定します。
- Spring Securityに対する設定
@Configuration public class SecurityConfig { // role-start @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { return http .authorizeHttpRequests(authorize -> authorize .requestMatchers("/admin/**").hasRole("admin") .requestMatchers("/user/**").hasRole("user") .anyRequest().authenticated()) .formLogin(form -> form .loginPage("/login") .usernameParameter("username") .passwordParameter("password") .defaultSuccessUrl("/top", true) .permitAll()) .logout(logout -> logout .logoutSuccessUrl("/login?logout") .invalidateHttpSession(true) .permitAll()) .headers(configurer -> configurer .referrerPolicy(referrer -> referrer .policy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN))) .build(); } @Bean public RoleHierarchy roleHierarchy() { // 権限の階層構造の設定をします。 // admin権限は、user権限を含む権限となります。 RoleHierarchyImpl hierarchy = new RoleHierarchyImpl(); hierarchy.setHierarchy("ROLE_admin > ROLE_user"); return hierarchy; } // role-end @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
ユーザ情報を取得するため、Doma2を使用してユーザ情報を取得するためのDaoとServiceを作成します。 ServiceではSpring Securityが提供している UserDetailService を実装し、Bean定義することで、Spring Securityから呼び出されます。
- Dao
@Dao @ConfigAutowireable public interface UserDao { @Select Optional<UserEntity> loadUserByUserName(String username); @Select List<String> loadUserRoles(String username); }
- SQL
select /*%expand*/* from users where username = /*username*/'username'
- Service
// UserDetailsServiceを実装して、ユーザ名に紐づく情報を取得するloadUserByUsernameメソッドを実装します。 @Service public class UserService implements UserDetailsService { private final UserDao userDao; public UserService(UserDao userDao) { this.userDao = userDao; } @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // Daoを使用してユーザ情報を取得します。 // ユーザ情報が存在しない場合には、UsernameNotFoundExceptionを送出し // Spring Security側での認証エラーの処理が行われるようにします。 return userDao.loadUserByUserName(username) // ユーザ情報には、ログインユーザに割り当てられた権限(ロール)も設定します。 .map(e -> new User(e.getUsername(), e.getPassword(), loadAuthorities(e.getUsername()))) .orElseThrow(() -> new UsernameNotFoundException("user not found.")); } /** * ユーザ名に紐づく権限リストを取得します。 * * @param username ユーザ名 * @return ユーザ名に紐づく権限リスト(存在しない場合は空のリスト) */ private List<GrantedAuthority> loadAuthorities(String username) { return userDao.loadUserRoles(username) .stream() .map(SimpleGrantedAuthority::new) .collect(toList()); } }
サンプル全体は table-authentication-sample を参照してください。