Две страницы входа с Spring Security
1. Вступление
В этом руководстве мы увидим, как мы можемconfigure Spring Security to work with two different login pages, используя два разных элемента Spring Securityhttp в конфигурации.
2. Настройка 2-х HTTP-элементов
Одна из ситуаций, в которой нам могут понадобиться две страницы входа, - это когда у нас есть одна страница для администраторов приложения и другая страница для обычных пользователей.
Мы будемconfigure two http elements, которые будут различаться по шаблону URL, связанному с каждым:
-
/user * для страниц, для доступа к которым потребуется обычная аутентификация пользователя
-
/admin * для страниц, к которым будет обращаться администратор
Каждый элементhttp будет иметь другую страницу входа и другой URL обработки входа.
Чтобы настроить два разных элементаhttp, давайте создадим два статических класса, аннотированных@Configuration, которые расширяютWebSecurityConfigurerAdapter.
Оба будут помещены в обычный класс@Configuration:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
...
}
Давайте определимWebSecurityConfigurerAdapter для пользователей“ADMIN”:
@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-адреса.
Два класса конфигурации не могут иметь одинаковый порядок.
3. Пользовательские страницы входа
Мы создадим наши собственные страницы входа для каждого типа пользователей. Для пользователя-администратора форма входа будет иметь действие“user_login”, как определено в конфигурации:
User login page
Страница входа администратора аналогична, за исключением того, что форма будет иметь действие“admin_login” в соответствии с конфигурацией java.
4. Конфигурация аутентификации
Теперь нам нужноconfigure authentication for our application. Давайте рассмотрим два способа добиться этого: один с использованием общего источника для аутентификации пользователя, а другой с использованием двух разных источников.
4.1. Использование общего источника аутентификации пользователя
Если обе страницы входа в систему имеют общий источник для аутентификации пользователей, вы можете создать один bean-компонент типаUserDetailsService, который будет обрабатывать аутентификацию.
Давайте продемонстрируем этот сценарий, используяInMemoryUserDetailsManager, который определяет двух пользователей - одного с ролью“USER” и одного с ролью“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. Использование двух разных источников аутентификации пользователей
Если у вас есть разные источники аутентификации пользователей - один для администраторов и один для обычных пользователей - вы можете настроитьAuthenticationManagerBuilder внутри каждого статического класса@Configuration. Давайте посмотрим на пример диспетчера аутентификации для пользователя“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");
}
}
В этом случае bean-компонентUserDetailsService из предыдущего раздела больше не будет использоваться.
6. Заключение
В этом кратком руководстве мы показали, как реализовать две разные страницы входа в одно и то же приложение Spring Security.
Полный код этой статьи можно найти вGitHub project.
Когда вы запускаете приложение, вы можете получить доступ к примерам выше по URI/protectedLinks.