###データベース認証の流れ
1.ProviderManagerはフィルターからの依頼を受ける
2.ProviderManagerはDaoAuthenticationProviderに認証処理を任せる
3.DaoAuthenticationProviderはUserDetailsServiceインターフェイス(電話)にユーザー情報を持って来いと電話をかける
4.UserDetailsServiceの実装クラスのMyUserDetailsServiceは電話をとりデータベースからユーザー情報を持ってくる
5.MyUserDetailsServiceはMyUserDetailsにユーザー情報を教えてUserDetailsを作るように指示する
6.MyUserDetailsが作成したユーザー情報を受け取ったDaoAuthenticationProviderはクライアントから入力された情報とを見比べる
7.間違っていれば「違うぞ!」と声を発する
#####UserDetails
ユーザー名とパスワード、ユーザーの情報を持っておくための書類
以下のメソッドが定義されている
######UserDetailsインターフェイス
public interface UserDetails extends Serializable {
String getUsername();
String getPassword();
boolean isEnabled();
boolean isAccountNonLocked();
boolean isAccountNonExpired();
boolean isCreditialsNonExpired();
Collection<? extends GrantedAuthority> getAuthorities();
}
getUsernameはユーザー名を返却する
getPasswordは登録されているパスワードを返却する
返却値と入力値を比べる
isEnabledはユーザーが有効かを判定
isAccountNonLockedはアカウントロックがされていないかを判定
isAccountNonExpiredはアカウントの有効期限を判定
isCreditialsNonExpiredは資格の有効期限を判定
getAuthoritiesは認可リストを返却する
###UserDetailsの実装クラス
public class AccountUserDetails implements UserDetails {
private final Account account;
private final Collection<GrantedAuthority> authorities;
public AccountUserDetails(
Account account, Collection<GrantedAuthority> authorities) {
this.account = account;
this.authorities = authorities;
}
public String getPassword() {
return account.getPassword();
}
public String getUsername() {
return account.getUsername();
}
public boolean isEnabled() {
return account.isEnabled();
}
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
public boolean isAccountNonExpired() {
return true;
}
public boolean isAccountNonLocked() {
return true;
}
public boolean isCredentialsNonExpired() {
return true;
}
public Account getAccount() {
return account;
}
}
Account accountがユーザー情報
Collection authoritiesが認可情報
isAccountNonExpired,isAccountNonLocked,isCredentialsNonExpiredはすべてOKを返す仕様
getAccountアカウント情報へのアクセスを可能にしている
###Account
package security.domain;
public class Account {
private String username;
private String password;
private String firstName;
private String lastName;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
###UserDetailsService
資格情報とユーザーの状態をデータベースから取得するインターフェイス
一緒にUserDetailsServiceインターフェイスを実装したクラスを作る
#####UserDetailsServiceインターフェイス
public interface UserDetailsService {
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
loadUserByUsernameはUserDetailsの作り方
###UserDetailsServiceの実装クラス
@Service
public class AccountUserDetailsService implements UserDetailsService {
@Autowired
AccountRepository accountRepository;
@Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
Account account = Optional.ofNullable(accountRepository.findOne(username))
.orElseThrow(() -> new UsernameNotFoundException("user not found."));
return new AccountUserDetails(account, getAuthorities(account));
}
private Collection<GrantedAuthority> getAuthorities(Account account) {
if(account.isAdmin()) {
return AuthorityUtils.createAuthorityList("ROLE_USER", "ROLE_ADMIN");
} else {
return AuthorityUtils.createAuthorityList("ROLE_USER");
}
}
}
Optional.ofNullable(accountRepository.findOne(username)).orElseThrow(() -> new UsernameNotFoundException("user not found."))
この分はラムダ式でOptional.ofNullableを呼び出しています
引数のaccountRepository.findOne(username)の結果がnullならば、orElseThrowが実行されてUsernameNotFoundException例外がthrowされます
次のリターン分でUserDetailsを作ります
getAuthoritiesユーザーがadminならその情報を作ります
###認証の適用
#####security-config.xml
sec:authentication-manager
<sec:authentication-provider
user-service-ref="accountUserDetailsService">
<bean id="passwordEncoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
AuthenticationManagerのBeanを定義します
sec:authentication-provideruser-service-ref="accountUserDetailsService"でDaoAuthenticationProviderに作成したUserDetailsServiceを指定します
DaoAuthenticationProviderにパスワードエンコーダーを設定しておきます
###まとめ
研修中の身なので、間違いなどありましたらご指摘願いたいです。