Рубрики
Без рубрики

Перенаправление на разные страницы после входа в систему с помощью Spring Security

Пример того, как перенаправлять на разные страницы после входа в систему с помощью Spring Security.

Автор оригинала: Eugen Paraschiv.

1. Обзор

Общим требованием для веб-приложения является перенаправление различных типов пользователей на разные страницы после входа в систему . Примером этого может быть перенаправление стандартных пользователей на /homepage.html пользователи страницы и администратора в /console.html страница, например.

В этой статье будет показано, как быстро и безопасно реализовать этот механизм с помощью Spring Security. Эта статья также основана на учебнике Spring MVC, который посвящен настройке основных материалов MVC, необходимых для проекта.

2. Конфигурация безопасности Spring

Spring Security предоставляет компонент, который несет прямую ответственность за принятие решения о том, что делать после успешной аутентификации – AuthenticationSuccessHandler .

2.1. Базовая конфигурация

Давайте сначала настроим базовый @Configuration и @Service класс:

@Configuration
@EnableWebSecurity
public class SecSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            // ... endpoints
            .formLogin()
                .loginPage("/login.html")
                .loginProcessingUrl("/login")
                .defaultSuccessUrl("/homepage.html", true)
            // ... other configuration       
    }
}

Часть этой конфигурации, на которой следует сосредоточиться, – это метод defaultSuccessUrl () . После успешного входа в систему любой пользователь будет перенаправлен на homepage.html .

Кроме того, нам необходимо настроить пользователей и их роли. Для целей этой статьи мы реализуем простой Userdetailsservice с двумя пользователями, каждый из которых имеет одну роль. Подробнее об этой теме читайте в нашей статье Spring Security – Роли и привилегии .

@Service
public class MyUserDetailsService implements UserDetailsService {

    private Map roles = new HashMap<>();

    @PostConstruct
    public void init() {
        roles.put("admin2", new User("admin", "{noop}admin1", getAuthority("ROLE_ADMIN")));
        roles.put("user2", new User("user", "{noop}user1", getAuthority("ROLE_USER")));
    }

    @Override
    public UserDetails loadUserByUsername(String username) {
        return roles.get(username);
    }

    private List getAuthority(String role) {
        return Collections.singletonList(new SimpleGrantedAuthority(role));
    }
}

Также обратите внимание, что в этом простом примере мы не будем использовать кодер паролей, поэтому пароли имеют префикс {noop} .

2.2. Добавление пользовательского обработчика успеха

Теперь у нас есть два пользователя с двумя разными ролями: пользователь и администратор . После успешного входа в систему оба будут перенаправлены на hompeage.html . Давайте посмотрим, как у нас может быть другой редирект в зависимости от роли пользователя.

Во-первых, нам нужно определить пользовательский обработчик успеха как компонент:

@Bean
public AuthenticationSuccessHandler myAuthenticationSuccessHandler(){
    return new MySimpleUrlAuthenticationSuccessHandler();
}

А затем замените вызов defaultSuccessUrl методом Обработчик успеха , который принимает ваш пользовательский обработчик успеха в качестве параметра:

@Override
protected void configure(final HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
        // endpoints
        .formLogin()
            .loginPage("/login.html")
            .loginProcessingUrl("/login")
            .successHandler(myAuthenticationSuccessHandler())
        // other configuration      
}

2.3. Конфигурация XML

Прежде чем перейти к реализации нашего пользовательского обработчика успеха, давайте также рассмотрим эквивалентную конфигурацию XML:


    
    
    





    
        
            
            
        
    

3. Пользовательский Обработчик Успеха Проверки Подлинности

Помимо интерфейса AuthenticationSuccessHandler , Spring также предоставляет разумное значение по умолчанию для этого компонента стратегии – AbstractAuthenticationTargetUrlRequestHandler и простую реализацию – SimpleUrlAuthenticationSuccessHandler . Обычно эти реализации определяют URL-адрес после входа в систему и выполняют перенаправление на этот URL-адрес.

Несмотря на некоторую гибкость, механизм определения этого целевого URL – адреса не позволяет выполнять определение программно, поэтому мы собираемся реализовать интерфейс и предоставить пользовательскую реализацию обработчика успеха. Эта реализация будет определять URL-адрес для перенаправления пользователя после входа в систему на основе роли пользователя.

Прежде всего, нам нужно переопределить метод onAuthenticationSuccess :

public class MySimpleUrlAuthenticationSuccessHandler
  implements AuthenticationSuccessHandler {
 
    protected Log logger = LogFactory.getLog(this.getClass());

    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, 
      HttpServletResponse response, Authentication authentication)
      throws IOException {
 
        handle(request, response, authentication);
        clearAuthenticationAttributes(request);
    }

Наш индивидуальный метод вызывает два вспомогательных метода:

protected void handle(
        HttpServletRequest request,
        HttpServletResponse response, 
        Authentication authentication
) throws IOException {

    String targetUrl = determineTargetUrl(authentication);

    if (response.isCommitted()) {
        logger.debug(
                "Response has already been committed. Unable to redirect to "
                        + targetUrl);
        return;
    }

    redirectStrategy.sendRedirect(request, response, targetUrl);
}

Где следующий метод выполняет фактическую работу и сопоставляет пользователя с целевым URL-адресом:

protected String determineTargetUrl(final Authentication authentication) {

    Map roleTargetUrlMap = new HashMap<>();
    roleTargetUrlMap.put("ROLE_USER", "/homepage.html");
    roleTargetUrlMap.put("ROLE_ADMIN", "/console.html");

    final Collection authorities = authentication.getAuthorities();
    for (final GrantedAuthority grantedAuthority : authorities) {
        String authorityName = grantedAuthority.getAuthority();
        if(roleTargetUrlMap.containsKey(authorityName)) {
            return roleTargetUrlMap.get(authorityName);
        }
    }

    throw new IllegalStateException();
}

Обратите внимание, что этот метод вернет сопоставленный URL-адрес для первой роли пользователя. Таким образом, если у пользователя несколько ролей, сопоставленный URL-адрес будет соответствовать первой роли, указанной в коллекции authorities .

protected void clearAuthenticationAttributes(HttpServletRequest request) {
    HttpSession session = request.getSession(false);
    if (session == null) {
        return;
    }
    session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
}

determineTargetUrl – который является ядром стратегии – просто смотрит на тип пользователя (определяется авторитетом) и выбирает целевой URL-адрес на основе этой роли .

Таким образом, пользователь admin – определенный ROLE_ADMIN authority – будет перенаправлен на страницу консоли после входа в систему, в то время как стандартный пользователь – определенный ROLE_USER – будет перенаправлен на домашнюю страницу.

4. Заключение

Как всегда, код, представленный в этой статье, доступен на GitHub . Это проект на основе Maven, поэтому его должно быть легко импортировать и запускать как есть.