UserDetails と UserDetailsService:ユーザー情報を扱うコンポーネントを理解しよう
Spring Security は、認証機能の主要な処理を実行するクラスを提供しています。 そのため、各アプリケーションに認証機能を実装する際には、アプリケーション固有の処理が必要な部分だけをカスタマイズします。
UserDetails
と UserDetailsService
は、Spring Security の挙動をカスタマイズする際に登場するインターフェースです。
このレクチャーでは、これらのインターフェースがどのような役割を持つか、また、どのように実装クラスを作成するかを解説します。
目次
UserDetails とは?
UserDetails
はユーザー情報を保持するインターフェースです。
Spring Security が提供しています。
このインターフェースには、以下のようなメソッドが定義されています
public interface UserDetails extends Serializable {
Collection<? extends GrantedAuthority> getAuthorities();
String getPassword();
String getUsername();
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
}
これらのメソッドは、以下のようなユーザーの情報を取得するためのものです:
getAuthorities()
:権限を返しますgetPassword()
:パスワードを返しますgetUsername()
:ユーザー名を返しますisAccountNonExpired()
:アカウントの有効期限が切れていないかを返しますisAccountNonLocked()
:アカウントがロックされていないかを返しますisCredentialsNonExpired()
:アカウントの認証情報の有効期限が切れていないかを返しますisEnabled()
:アカウントが有効かを返します
Spring Security に対して、ユーザー情報を提供する際には、このインターフェースを実装したクラスを作成します。
UserDetailsService とは?
UserDetailsService
は、UserDetails
オブジェクトを取得するためのインターフェースです。
以下のように定義されています:
public interface UserDetailsService {
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
UserDetailsService
インターフェースには、loadUserByUsername
メソッドだけが定義されています。
loadUserByUsername
は、ユーザー名を引数に取り、UserDetails
オブジェクトを返します。
loadUserByUsername
メソッドの内部では、ユーザー情報が保存されているデータベースやファイルなどから、ユーザー情報を取得する処理を記述します。
どこからユーザー情報を取得するかは、アプリケーションによって自由に決めることができます。
UserDetailsService
インターフェースの実装
UserDetailsService
はインターフェースです。
アプリケーションで処理を実現するには、このインターフェースを implements した実装クラスを作成する必要があります。
次の UserService
クラスは UserDetailsService
インターフェースの実装クラスの例です:
@Service
@RequiredArgsConstructor
public class UserService implements UserDetailsService {
private final UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return userRepository.findByUsername(username)
.map(u -> User.builder()
.username(u.username())
.password(u.password())
.build()
)
.orElseThrow(() -> new UsernameNotFoundException(username + " not found"));
}
}
このクラスは、指定されたユーザー名に基づいてユーザー情報をデータベースから取得し、UserDetails
オブジェクトを作成します。
データベースへのアクセスは、UserRepository
クラスに委譲しています。
User.builder()
は、UserDetails
インターフェースを実装した User
クラスのビルダーです。
User
クラスは Spring Security が提供しているクラスです。
複雑なカスタマイズする必要がなければ、独自のクラスを定義せずこのクラスを使うこともできます。
UserDetailsService
の実装クラスを Spring Security と統合する方法
UserDetailsService
クラスの実装クラスを作成したら、Spring Security に統合することで、アプリケーション固有のユーザー認証ロジックを実現できます。
以下のようなコードを SecurityConfig
クラスに追加することで、UserDetailsService
の実装クラスを統合できます:
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final UserDetailsService userDetailsService;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.userDetailsService(userDetailsService)
// ...
;
return http.build();
}
上記のコードでは、UserDetailsService
を DI によって取得し、HttpSecurity#userDetailsService
メソッドに渡しています。
まとめ:UserDetails と UserDetailsService の役割と実装方法
今回は UserDetails
と UserDetailsService
の役割と実装方法を学びました。
UserDetails
はユーザー情報を保持するためのインターフェースですUserDetailsService
はユーザー情報を取得するためのインターフェースですUserDetailsService
インターフェースを implements するクラスを作成し、Spring Security に統合することで、アプリケーション固有のユーザー認証ロジックを実装できます