LoginSignup
3
5

More than 1 year has passed since last update.

SpringBoot基礎 ログイン認証のカスタマイズ

Last updated at Posted at 2022-03-21

ログインユーザ情報の構成

image.png

SecurityContextHolder SecurityContextを保持する
SecurityContext セキュリティに関わる情報を保持する
Authentication 認証トークンを保持する
Principal ログインユーザ情報を保持する
Credentials ユーザID、パスワード等を保持する
Authorities 権限情報を保持する

基本的な認証に必要な設定あれこれ

SecurityConfigファイル

SecurityConfigファイルのサンプル
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{

    // 認証項目カスタマイズ時は指定
    @Autowired
    @Qualifier("UserDetailsServiceImpl")
    private UserDetailService userDetailsService

    // 独自のログイン認証を実装する場合は指定
    @Autowired
    @Qualifier("TestAuthenticationProvider")
    private AuthenticationProvider authenticationProvider 
   
    @Override
    protected void configure(HttpSecurity http) throws Exception{
        //ログイン認証不要なページ、直リンク禁止ページを設定
        http
          .authorizeRequests()
            //ログイン無しでアクセスOK
            .antMatchers("/login").permitAll()
            //上記以外はログインが必要
            .anyRequest().authenticated();
        //ログイン処理
        http
          .formLogin()
            //ログイン処理時のパス
            .loginProcessingUrl("/login")
            //ログインページの指定
            .loginPage("/login")
            //ログイン失敗時の遷移先
            .failreUrl("/login?error")
            //ユーザIDパラメータ名 ※login.htmlのnameに指定
            .usernameParameter("userId")
            //パスワードパラメータ名 ※login.htmlのnameに指定
            .passwordParameter("password")
            //ログイン後の遷移先
            .defaultSuccessUrl("/home")

            //(カスタマイズ)ログイン後の遷移先を制御 ※別途クラス作成が必要
            .successHandler(successHandler)

        //ログアウト処理
        http
          .logout()
            //ログアウト処理時のパス
            .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
            //ログアウトページの指定
            .logoutUrl("/logout")
            //ログアウト後の遷移先
            .logoutSuccessUrl("/login");
    }
    
    // 認証項目カスタマイズ時は指定
    @Orverride
    protected void configure(Authentication ManagerBuilder auth) throws Exception{
        // 1.独自のログイン認証を実装しない場合且つ、ログイン処理時のユーザ情報をDBから取得する場合
        auth.userDetailService(userDetailsService).passwordEncoder(passwordEncoder());

        // 2.独自のログイン認証を実装する場合
        auth.authenticationProvider(authenticationProvider)

    }
}

ログイン画面のコントローラー

コントローラークラスのサンプル
@Controller
public class LoginController{
    @GetMapping("/login")
    public String init(){
        return "login";
    }
}

ログイン後遷移先のコントローラー

コントローラークラスのサンプル①
@Controller
public class HomeController{

    @GetMapping("/home")
    public String init(Model model, Principal principal){

        // SecurityContextHolderからユーザ情報を取得する
        Authentication authentication = (Authentication) principal;
        User user = (User) authentication.getprincipal();

        /** ログイン後の任意処理 */
        // user.toString()でユーザ情報を取得可能
        
        return "home";
    }
}

@AuthenticationPrincipalを使用することでUser情報取得を省略可能

コントローラークラスのサンプル②
@Controller
public class HomeController{

    // ※
    @GetMapping("/home")
    public String init(Model model, @AuthenticationPrincipal User user){

        /** ログイン後の任意処理 */
        // user.toString()でユーザ情報を取得可能

        return "home";
    }
}

指定しているUserクラスはSpringのクラス。カスタマイズする場合は変更が必要

ログイン後のhtml画面

sec:authentication属性で、ユーザIDなら「name」、ロールなら「principal.authorities」でユーザ情報を取得可能

home.html

//省略

// ユーザIDの取得
<p>ユーザID:<span sec:authentication="name"></span>

// ロールの取得
<p>ロール:<span sec:authentication="principal.authorities"></span>

// 認証項目カスタマイズ時は指定
<p>ユーザID:<span sec:authentication="principal.username"></span> 
<p>任意項目:<span sec:authentication="principal.[userDetailsの実装クラスに指定したフィールド]"></span>

//省略


独自ユーザクラスの作成

UserDetailsクラス

DBからユーザを取得する際は下記のクラスを使用

DaoAuthenticationProvider DBからユーザを取得して認証処理を行うクラス。Authentication、Principalにユーザ情報を設定する。パスワードチェックもこのクラスが提供する。
UserDetailsService ユーザIDからユーザ情報を取得するインターフェース。このクラスを実装したクラスでDB取得処理を実装し、独自ユーザクラスを生成する。
UserDetails ユーザクラス用のインターフェース。このクラスを実装したクラスが独自ユーザクラスとなる。

UserDetaiols:userNameフィールドはSpringのデフォルトでユーザIDとしてみなされるため注意

独自のログイン認証を実装

通常、ログインIDとパスワードで認証をおこなうところ、テナントIDなども認証項目として利用したいケース。

image.png

AuthenticationFilter URLリクエストに対し、Authentication(認証情報)を作成。それをAuthenticationManagerに渡して、認証処理を呼び出す。
AuthenticationManager AuthenticationProviderを管理。認証処理自体はAuthenticationProviderで実行される。複数のAuthenticationProviderを順番に呼び出し、一つでも認証成功となれば認証OKとなる。
AuthenticationProvider 認証処理を実装する。
AuthenticationProviderのサンプル
@Component("TestAuthenticationProvider")
public class TestAuthenticationProvider implements AuthenticaitonProvider {
    /** 認証処理を実装 */
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        
        // 独自の認証処理を実装
        
        // UsernamePasswordAuthenticationTokenには権限のsetterがないため、新たなインスタンスを生成する。
        return new UsernamePasswordAuthenticationToken(principal, credentials, authorities)
        
    }

    /** 認証対象のクラスを制限するためのメソッド。
     *   今回は[UsernamePasswordAuthenticationToken]だけを認証対象にしている
     */
    @Override
    public boolean supports(Class<?> authentication) {
        return UsernamePasswordAuthenticationToken.class.isAddignableForm(authenticaiton);
    }
}
3
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
3
5