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에서 위의 예제에 액세스할 수 있습니다.