一尘不染

Spring Security,注销:将参数从/ logout传递到/ login

spring-boot

我正在使用默认的Spring Security来处理注销/登录。我有一个处理的Controller方法/login

注销后,我看到Spring
Security将我重定向到app/login?logout。这个Spring创建的参数(有时也存在app/login?error)的存在使我可以将Login处理程序编写为:

@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

从我的应用程序中,我发出以下Spring Security注销URL(注销是自动的,因此我没有针对它的特定处理程序):

myapp.com/app/logout?exitMsg=MyMessage

立即,登录处理程序会丢失此参数,而我没有。

我考虑编写自己的/logout处理程序,在该程序中我手动注销(使会话无效),然后使用此参数重定向到“登录我自己”。这是这里的建议。但是,如果这样做,
我将失去获得Spring的自动
?logout?error请求参数的能力。在自动场景中,我正在获取它们,但现在没有。我只得到自己指定的自定义参数。我需要保留?logout并且?error还要测试自己的新参数。

任何想法高度赞赏。

Spring安全配置:

    @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();
    }

阅读 1508

收藏
2020-05-30

共1个答案

一尘不染

您需要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");
}

我考虑过写自己的/ logout处理程序

实际上,这不是注销处理程序,而是注销启动器。
使用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");
        }
    }
}

从我的应用程序中,我发出了这个Spring Security注销URL(注销是自动的,因此我没有特定的处理程序)

servlet / spring安全性没有自动注销功能。只有我们能实现的是
1.自动化客户端以发送注销请求
。2.在服务器中,我们可以设置会话的maxInactiveInterval,以便可以通过删除cookie
/将cookie的使用期限设置为过去的日期来使会话无效。一旦会话对下一个请求无效,spring安全过滤器链中的一个过滤器会将其重定向到/ param过期的/
login页面。/login?expired
如果您启动注销,spring security将删除cookie /使会话无效,并使用param注销重定向到/
login页面。/login?logout
在Spring Security中,有两种配置可以实现注销。

.and().logout()
.invalidateHttpSession(true)
//or
.deleteCookies("JSESSIONID")

编辑:看到OP的答案后。 缺少在此处添加的信息。OP和我在临时答案(该聊天和答案已被删除)中进行了长时间聊天,我们在其中找到了 LOGIN-
WALL

“登录墙”是配置错误的结果,您将在其中定义一个自定义登录页面,并将其配置为在身份验证后允许访问的资源。(access=isAuthenticated),但如果我们在使会话无效的情况下重定向到登录页面,则从CustomLogoutSuccessHandler进行弹簧安全性阻止登录页面访问(401-未授权),因为该页面仅允许经过身份验证的用户使用。阻止Spring安全性后,将负责重定向到配置中配置的页面。`.loginPage(“
/ someloginpage”)。它迫使人们认为注销正确发生,可以正确重定向到登录页面,但是我在查询字符串中发送的参数没有进入登录页面。
如果我称其为难题,那没错,这很难猜

2020-05-30