LoginSignup
2
5

More than 5 years have passed since last update.

Spring Security データベースの認証

Posted at

データベース認証の流れ

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">
        <sec:password-encoder ref="passwordEncoder" />
    </sec:authentication-provider>
</sec:authentication-manager>

<bean id="passwordEncoder"
    class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />

AuthenticationManagerのBeanを定義します

sec:authentication-provideruser-service-ref="accountUserDetailsService"でDaoAuthenticationProviderに作成したUserDetailsServiceを指定します
DaoAuthenticationProviderにパスワードエンコーダーを設定しておきます

まとめ

研修中の身なので、間違いなどありましたらご指摘願いたいです。

2
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
5