Spring Security, Logout: передать параметр из / logout в / login - PullRequest
2 голосов
/ 26 сентября 2019

Я использую Spring Security по умолчанию для обработки выхода из системы / входа в систему.У меня есть метод Controller, который обрабатывает /login.

. Когда я выхожу из системы, я вижу, что Spring Security перенаправляет меня на app/login?logout.Наличие этого параметра, созданного Spring (а иногда и app/login?error), позволяет мне написать свой обработчик входа в систему как:

@GetMapping("/participant/login")
public ModelAndView  loginPage(HttpServletRequest request, HttpServletResponse response, 
        @RequestParam(value = "error", required = false) String error,
        @RequestParam(value = "logout", required = false) String logout) {
    log.info("Entering participant login page");
    ModelAndView mav = new ModelAndView(LOGIN_JSP);
    if (null != error) {
        // We're coming to the login page after an Error
        mav.addObject("info", "My generic error message");
    } else if(null != logout){
        // We're coming to the login page after a Logout
        mav.addObject("info", "My generic logout message");
    }
    // ...Otherwise, normal Login page, no extra information

Теперь проблема в том, что когда я выхожу из системы, мне нужно передать пользовательский параметр в / logout с передачей в / login .Цель состоит в том, чтобы мне нужно было получить параметр в /login, который я могу исследовать точно так же, как созданные системой error и logout.

Предположим, что этот пользовательский параметр равен exitMsg.

Из моего приложения я выдаю URL-адрес Spring Security Logout (выход из системы автоматический, поэтому у меня нет специального обработчика для него):

myapp.com/app/logout?exitMsg=MyMessage

Сразу же, ЛогинОбработчик теряет этот параметр, а у меня его нет.

Я подумал о том, чтобы написать собственный обработчик /logout, в котором я вручную выхожу из системы (лишает законной силы сеанс), а затем перенаправляю себя в Login с этим параметром.Это предложение здесь .Но если я сделаю это, я потеряю возможность автоматически получать параметры Spring ?logout и ?error Request.В автоматическом сценарии я их получал, а сейчас нет.Я получаю только пользовательский параметр, который я указываю сам.Мне нужно сохранить ?logout и ?error, а также проверить мой новый параметр.

Любые мысли высоко ценятся.

Spring Security Config:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/participant/**").authorizeRequests()
                .antMatchers("/participant/id/**").permitAll()
                .antMatchers("/participant/faq").permitAll()
                .antMatchers("/participant/forgetPassword").permitAll()
                .antMatchers("/participant/securityQuestions").permitAll()
                .antMatchers("/participant/securityCheck").permitAll()
                .antMatchers("/participant/resetPassword").permitAll()
                .antMatchers("/participant/**").authenticated()
            .and()
                .formLogin().loginPage("/participant/login").permitAll()
                .failureUrl("/participant/login?error").permitAll()
                .defaultSuccessUrl("/participant/home")
                .usernameParameter("username").passwordParameter("password")
            .and()
                .logout().logoutUrl("/participant/logout")
                .logoutSuccessUrl("/participant/login?logout").permitAll()
            .and()
                .csrf().disable();
    }

Ответы [ 2 ]

1 голос
/ 26 сентября 2019

Вам нужно logoutSuccessHandler вместо .logoutSuccessUrl("/login?logout")
Настроить logoutSuccessHandler, как указано ниже

@Override
protected void configure(final HttpSecurity http) throws Exception
{
    http
        .authorizeRequests()
            .antMatchers("/resources/**", "/", "/login", "/api/**")
                .permitAll()
            .antMatchers("/app/admin/*")
                .hasRole("ADMIN")
            .antMatchers("/app/user/*")
                .hasAnyRole("ADMIN", "USER")
        .and().exceptionHandling().accessDeniedPage("/403")
        .and().formLogin()
            .loginPage("/login").usernameParameter("userName")
            .passwordParameter("password")
            .defaultSuccessUrl("/app/user/dashboard")
            .failureUrl("/login?error=true")
        .and().logout()
            .logoutSuccessHandler(new CustomLogoutSuccessHandler())
            .invalidateHttpSession(true)
        .and().csrf().disable();

    http.sessionManagement().maximumSessions(1).expiredUrl("/login?expired=true");
}

Я подумал написать свой собственный обработчик / обработчик выхода из системы

На самом деле это не обработчик выхода из системы, а инициатор выхода из системы.
Используйте CustomLogoutSuccessHandler, где вы можете получить параметры запроса и установить его снова, как указано ниже.

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;

public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler
{

    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException
    {
        Cookie cookie = new Cookie("JSESSIONID", null);
        cookie.setPath(request.getContextPath());
        cookie.setMaxAge(0);
        response.addCookie(cookie);

        if(request.getParameter("expired") != null)
        {
            response.sendRedirect(request.getContextPath()+"/login?expired=true");
        }
        else
        {
            response.sendRedirect(request.getContextPath() + "/login?logout=true");
        }
    }
}

Из моего приложения я выдаю этот URL-адрес Spring Security Logout (выход из системы автоматический, поэтому у меня нет специального обработчика для него)

В системе безопасности сервлетов / пружин отсутствует функция автоматического выхода из системы.Единственное, чего мы можем достичь, это
1. Автоматизировать клиента для отправки запроса на выход
2. На сервере мы можем установить maxInactiveInterval сеанса, чтобы сеанс можно было аннулировать, удалив cookie / установив возраст cookie в прошлом.После того, как сеанс признан недействительным для следующего запроса, один из фильтров в цепочке фильтров безопасности Spring перенаправляет его на страницу / login с истекшим параметром. /login?expired
Если вы инициируете выход из системы, Spring Security удалит cookie / сделает сеанс недействительным и перенаправит наСтраница входа с параметром выхода из системы. /login?logout
Существует два типа конфигурации выхода из системы в системе безопасности Spring.

.and().logout()
.invalidateHttpSession(true)
//or
.deleteCookies("JSESSIONID")
0 голосов
/ 27 сентября 2019

Несмотря на принятие ответа выше (спасибо Praveen за вашу помощь!), Единственное реальное решение, которое я нашел, это избегать поведения Spring по умолчанию logout-> login и использовать пользовательский обработчик Logout с новым выделенным JSP Logout выхода из системы,которая НЕ является страницей входа .Таким образом, я избежал перенаправления на страницу входа, у меня просто есть отдельная страница выхода - они больше не совпадают.Если пользователь хочет войти снова, он может ввести URL /app/login, чтобы войти в систему.

Обработчик выхода из системы - это обычный обработчик контроллера (я назвал его myLogout),

@GetMapping("/participant/myLogout")
public String myLogout(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // Just for testing, the param is available:
    System.out.println(request.getParameter("exitMsg");
    // Manual logoff
    CookieClearingLogoutHandler cookieClearingLogoutHandler = new CookieClearingLogoutHandler(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY);
    SecurityContextLogoutHandler securityContextLogoutHandler = new SecurityContextLogoutHandler();
    cookieClearingLogoutHandler.logout(request, response, null);
    securityContextLogoutHandler.logout(request, response, null);
    // My custom Logout JSP. No auto-redirects to Login
    return LOGOUT_JSP; 
}

И если вам нужен параметр, он есть как на сервере, так и на клиенте.сторона в JSP Logout:

     `${param.exitMsg}`:  --> Output: `test`. 

Все предложения о том, как перенаправить на Login с параметром - будь то реализация CustomLogoutSuccessHandler, такая как здесь или напрямую через перенаправление контроллеранапример здесь - не работает, если у вас есть требование «login-wall» для Spring Security Config

    // ... special URLs listed here, then at the end:
    .antMatchers("/participant/**").authenticated()

после вашего списка специальных разрешений.Это не работает, потому что Spring Security выполнит требование Login-Wall basic / login без параметров сначала , как только вы попытаетесь даже перенаправить на Login с параметром.И только тогда, после того как вы подтвердите свою подлинность, он будет использовать параметр перенаправления с параметром, например login?logout&exitMsg=....что ты просил.Другими словами, вы все равно потеряете параметр в вашем первом Требовании входа в стену, потому что вы уже вышли из системы.

Я не думаю, что мы должны избавляться от .authenticated() в Config, потому что именно это создает защиту Login-Wall для всех запросов, что является важной функцией безопасности.Но когда он у вас есть, вы не можете передавать параметры в /login, потому что базовая Login-Wall /login с NO параметрами всегда будет в первую очередь.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...