ti-tomo-knowledge.hatenablog.com
にて、アカウント情報の登録まで行いましたが、
次は実際にログイン機能を実装してみます。
※認証失敗時など、細かい処理まで書くと長くなってしまうので、今回は認証が必ず成功するパターンで書きます。
WebSecurityConfigurerAdapterを継承しているSpring Sercurityの設定クラスの中で、
「HttpSecurity http」を引数に持つconfigureメソッドの中に以下を追加してください。
http.formLogin() .loginProcessingUrl("/login") // 認証処理を起動させるパス .loginPage("/loginForm") // ログインフォームのパス .failureUrl("/loginForm/?error") // ログイン処理失敗時の遷移先 .defaultSuccessUrl("/") // 認証成功時の遷移先 .usernameParameter("email").passwordParameter("password"); // ユーザ名(今回はメールアドレスだけど)とパラメータ http.logout() .logoutRequestMatcher(new AntPathRequestMatcher("/logout**")) // ログアウト処理を起動させるパス .logoutSuccessUrl("/"); // ログアウト完了時のパス
また、同一クラスの中で以下のAuthenticationConfigurationクラスも追加してください。
@Configuration protected static class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter { @Autowired JpaUserDetailsServiceImpl userDetailsService; @Override public void init(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService) .passwordEncoder(new BCryptPasswordEncoder()); } }
このクラスは認証処理時に自動で呼ばれるクラスです。
やっていることは入力されたパスワードに対してBCryptでハッシュ化し、
入力値が正しいか認証を行っています。
この中で呼ばれているJpaUserDetailsServiceImplクラスについてですが、
以下のようにUserDetailsServiceクラスを継承する形で定義しています。
package test.package; import test.package.model.Account; import test.package.repository.AccountRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Component; @Component public class JpaUserDetailsServiceImpl implements UserDetailsService { @Autowired private AccountRepository accountRepository; @Override public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { Account account = accountRepository.findByEmail(email); return account; } }
findByEmailを実行するために、
AccountRepository内に下記を追加しておいてください。
Account findByEmail(String email);
さて、JpaUserDetailsServiceImplクラスのloadUserByUsernameでは、UserDetails形式で値を返すという宣言をしています。
よって通常のEntityクラスで値を返すことはできないので、accountRepositoryで取得するオブジェクト(Accountオブジェクト)は、UserDetails形式になるようにします。
実際の定義は以下のようになります。
package test.model; import lombok.Builder; import lombok.Data; import lombok.experimental.Tolerate; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import javax.persistence.*; import java.util.Collection; import java.util.Date; @Entity @Table(name = "accounts") @Data public class Account implements UserDetails { @Id @GeneratedValue private int id; @Column(nullable=false, unique = true) private String email; @Column(nullable=false, length=60) private String password; /* (非 Javadoc) * @see org.springframework.security.core.userdetails.UserDetails#getAuthorities() */ @Override public Collection<? extends GrantedAuthority> getAuthorities() { return null; } /* (非 Javadoc) * @see org.springframework.security.core.userdetails.UserDetails#getUsername() */ @Override public String getUsername() { return this.email; } /* (非 Javadoc) * @see org.springframework.security.core.userdetails.UserDetails#isAccountNonExpired() */ @Override public boolean isAccountNonExpired() { return true; } /* (非 Javadoc) * @see org.springframework.security.core.userdetails.UserDetails#isAccountNonLocked() */ @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } }
上記のようにEntityアノテーションを付けたクラスを定義し、UserDetailsインターフェースを継承しています。
UserDetailsはすでにSpring Security内のクラスですが、中身を見てみると以下のようになっています。
package org.springframework.security.core.userdetails; import java.io.Serializable; import java.util.Collection; import org.springframework.security.core.GrantedAuthority; public interface UserDetails extends Serializable { Collection<? extends GrantedAuthority> getAuthorities(); String getPassword(); String getUsername(); boolean isAccountNonExpired(); boolean isAccountNonLocked(); boolean isCredentialsNonExpired(); boolean isEnabled(); }
Serializableを継承しており、7つの抽象メソッドが定義されています。
なので、このインターフェースを継承したEntityクラスで、抽象メソッドをオーバーライドして実装する必要があります。
とりあえずこれでログイン処理は上手くいったので進めてみます。
- 出版社/メーカー: Amazon
- 発売日: 2017/04/06
- メディア: エレクトロニクス
- この商品を含むブログ (17件) を見る
新登場 Fire TV Stick 4K - Alexa対応音声認識リモコン付属
- 出版社/メーカー: Amazon
- 発売日: 2018/12/12
- メディア: エレクトロニクス
- この商品を含むブログを見る
Fire HD 10 タブレット (10インチHDディスプレイ) 64GB
- 出版社/メーカー: Amazon
- 発売日: 2017/10/11
- メディア: エレクトロニクス
- この商品を含むブログ (4件) を見る