1. 소개

이 예제에서는 구성에서 두 개의 다른 Spring Security http 요소를 사용하여 두 개의 다른 로그인 페이지에서 작동하도록 Spring Security를 ​​구성 하는 방법을 살펴봅니다.

2. 2개의 Http 요소 구성

두 개의 로그인 페이지가 필요한 상황 중 하나는 애플리케이션 관리자용 페이지 하나와 일반 사용자용 페이지 하나가 있는 경우입니다.

각각 연결된 URL 패턴으로 구분되는 두 개의 http 요소 를 구성합니다.

  • 액세스하려면 일반 사용자 인증이 필요한 페이지의 경우 /user*
  • /admin* 관리자 가 액세스할 페이지의 경우

http 요소에는 다른 로그인 페이지와 다른 로그인 처리 URL이 있습니다.

두 개의 서로 다른 http 요소 를 구성하기 위해 @Configuration 어노테이션이 달린 두 개의 정적 클래스를 만들어 보겠습니다 .

둘 다 일반 @Configuration 클래스 안에 배치됩니다.

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

"ADMIN" 사용자 를 위한 ConfigurerAdapter 를 정의해 보겠습니다 .

@Configuration
@Order(1)
public static class App1ConfigurationAdapter {

    @Bean
    public SecurityFilterChain filterChainApp1(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();
       return http.build();
    }
}

이제 일반 사용자를 위한 ConfigurerAdapter 를 정의해 보겠습니다.

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

    @Bean 
    public SecurityFilterChain filterChainApp2(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();
       return http.build();
    }
}

각 정적 클래스에 @Order 어노테이션을 배치하면 URL이 요청될 때 패턴 일치를 기반으로 두 클래스가 고려되는 순서를 지정합니다.

두 구성 클래스의 순서가 같을 수 없습니다.

3. 사용자 지정 로그인 페이지

각 유형의 사용자에 대해 고유한 사용자 정의 로그인 페이지를 생성합니다. 관리자 사용자의 경우 로그인 양식 에는 구성에 정의된 대로 "user_login" 작업이 있습니다.

<p>User login page</p>
<form name="f" action="user_login" method="POST">
    <table>
        <tr>
            <td>User:</td>
            <td><input type="text" name="username" value=""></td>
        </tr>
        <tr>
            <td>Password:</td>
            <td><input type="password" name="password" /></td>
        </tr>
        <tr>
            <td><input name="submit" type="submit" value="submit" /></td>
        </tr>
    </table>
</form>

관리자 로그인 페이지는 Java 구성에 따라 양식에 "admin_login" 작업이 있다는 점을 제외하면 비슷합니다.

4. 인증 구성

이제 애플리케이션에 대한 인증을 구성 해야 합니다 . 이를 수행하는 두 가지 방법을 살펴보겠습니다. 하나는 사용자 인증에 공통 소스를 사용하는 것이고 다른 하나는 두 개의 개별 소스를 사용하는 것입니다.

4.1. 일반 사용자 인증 소스 사용

두 로그인 페이지가 사용자 인증을 위한 공통 소스를 공유하는 경우 인증 을 처리할 UserDetailsService 유형의 단일 빈을 생성할 수 있습니다 .

두 명의 사용자( "USER" 역할을 가진 사용자 와 "ADMIN" 역할을 가진 사용자)를 정의 하는 InMemoryUserDetailsManager 를 사용하여 이 시나리오를 시연해 보겠습니다 .

@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. 서로 다른 두 개의 사용자 인증 소스 사용

사용자 인증을 위한 다른 소스가 있는 경우(하나는 관리자용, 다른 하나는 일반 사용자용) 각 정적 @Configuration 클래스 내에서 AuthenticationManagerBuilder 를 구성할 수 있습니다. "ADMIN" 사용자 에 대한 인증 관리자의 예를 살펴보겠습니다 .

@Configuration
@Order(1)
public static class App1ConfigurationAdapter {

    @Bean
    public UserDetailsService userDetailsServiceApp1() {
         UserDetails user = User.withUsername("admin")
             .password(encoder().encode("admin"))
             .roles("ADMIN")
             .build();
         return new InMemoryUserDetailsManager(user);
    }
}

이 경우 이전 섹션의 UserDetailsService 빈은 더 이상 사용되지 않습니다.

6. 결론

이 빠른 사용방법(예제)에서는 동일한 Spring Security 애플리케이션에서 두 개의 서로 다른 로그인 페이지를 구현하는 방법을 보여주었습니다.

이 기사의 전체 코드는 GitHub 프로젝트 에서 찾을 수 있습니다 .

애플리케이션을 실행하면 /protectedLinks URI에서 위의 예제에 액세스할 수 있습니다.

Security footer banner