Spring Securityの2つのログインページ

Spring Securityの2つのログインページ

1. 前書き

このチュートリアルでは、構成で2つの異なるSpring Securityhttp要素を使用してconfigure Spring Security to work with two different login pagesを実行する方法を説明します。

2. 2つのHttp要素の構成

2つのログインページが必要な状況の1つは、アプリケーションの管理者用のページと通常のユーザー用の別のページがある場合です。

それぞれに関連付けられたURLパターンによって区別されるconfigure two http elementsを実行します。

  • アクセスするために通常のユーザー認証が必要なページの場合は/user *

  • 管理者がアクセスするページの/admin *

http要素には、異なるログインページと異なるログイン処理URLがあります。

2つの異なるhttp要素を構成するために、WebSecurityConfigurerAdapterを拡張する@Configurationで注釈が付けられた2つの静的クラスを作成しましょう。

どちらも通常の@Configurationクラス内に配置されます。

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    ...
}

“ADMIN”ユーザーのWebSecurityConfigurerAdapterを定義しましょう。

@Configuration
@Order(1)
public static class App1ConfigurationAdapter extends WebSecurityConfigurerAdapter {
    public App1ConfigurationAdapter() {
        super();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/admin*")
          .authorizeRequests()
          .anyRequest()
          .hasRole("ADMIN")

          .and()
          .formLogin()
          .loginPage("/loginAdmin")
          .loginProcessingUrl("/admin_login")
          .failureUrl("/loginAdmin?error=loginError")
          .defaultSuccessUrl("/adminPage")

          .and()
          .logout()
          .logoutUrl("/admin_logout")
          .logoutSuccessUrl("/protectedLinks")
          .deleteCookies("JSESSIONID")

          .and()
          .exceptionHandling()
          .accessDeniedPage("/403")

          .and()
          .csrf().disable();
    }
}

それでは、通常のユーザーのWebSecurityConfigurerAdapterを定義しましょう。

@Configuration
@Order(2)
public static class App2ConfigurationAdapter extends WebSecurityConfigurerAdapter {

    public App2ConfigurationAdapter() {
        super();
    }

    protected void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/user*")
          .authorizeRequests()
          .anyRequest()
          .hasRole("USER")

          .and()
          .formLogin()
          .loginPage("/loginUser")
          .loginProcessingUrl("/user_login")
          .failureUrl("/loginUser?error=loginError")
          .defaultSuccessUrl("/userPage")

          .and()
          .logout()
          .logoutUrl("/user_logout")
          .logoutSuccessUrl("/protectedLinks")
          .deleteCookies("JSESSIONID")

          .and()
          .exceptionHandling()
          .accessDeniedPage("/403")

          .and()
          .csrf().disable();
    }
}

各静的クラスに@Orderアノテーションを配置することにより、URLが要求されたときに一致するパターンに基づいて2つのクラスが考慮される順序を指定していることに注意してください。

2つの構成クラスの順序を同じにすることはできません。

3. カスタムログインページ

ユーザーのタイプごとに独自のカスタムログインページを作成します。 管理者ユーザーの場合、ログインフォームには、構成で定義されているように、“user_login”アクションがあります。

User login page

User:
Password:

管理者のログインページも同様ですが、フォームにはJava構成に従って“admin_login”のアクションがあります。

4. 認証構成

ここで、configure authentication for our applicationにする必要があります。 これを実現する2つの方法を見てみましょう。1つはユーザー認証に共通のソースを使用する方法、もう1つは2つの別々のソースを使用する方法です。

4.1. 共通のユーザー認証ソースの使用

両方のログインページがユーザーを認証するための共通のソースを共有している場合、認証を処理するタイプUserDetailsServiceの単一のBeanを作成できます。

2人のユーザーを定義するInMemoryUserDetailsManagerを使用して、このシナリオを示しましょう。1つは“USER”の役割を持ち、もう1つは“ADMIN”の役割を持ちます。

@Bean
public UserDetailsService userDetailsService() throws Exception {
    InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
    manager.createUser(User
      .withUsername("user")
      .password(encoder().encode("userPass"))
      .roles("USER")
      .build());

    manager.createUser(User
      .withUsername("admin")
      .password(encoder().encode("adminPass"))
      .roles("ADMIN")
      .build());

    return manager;
}

@Bean
public static PasswordEncoder encoder() {
    return new BCryptPasswordEncoder();
}

4.2. 2つの異なるユーザー認証ソースの使用

ユーザー認証のソースが異なる場合(管理者用と通常ユーザー用)、各静的@Configurationクラス内にAuthenticationManagerBuilderを構成できます。 “ADMIN”ユーザーの認証マネージャーの例を見てみましょう。

@Configuration
@Order(1)
public static class App1ConfigurationAdapter extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
          .withUser("admin")
          .password(encoder().encode("admin"))
          .roles("ADMIN");
    }
}

この場合、前のセクションのUserDetailsServiceBeanは使用されなくなります。

6. 結論

このクイックチュートリアルでは、同じSpringSecurityアプリケーションに2つの異なるログインページを実装する方法を示しました。

この記事の完全なコードはGitHub projectにあります。

アプリケーションを実行すると、/protectedLinksURIで上記の例にアクセスできます。