当前位置: 首页 > 知识库问答 >
问题:

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

李建中
2023-03-14

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

当我注销时,我看到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中接收一个参数,我可以检查就像系统创建的errorlogout一样。

假设这个自定义参数是exitMsg

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

myapp。com/app/logout?exitsg=MyMessage

马上,登录处理程序就会丢失这个参数,而我没有它。

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

任何想法高度赞赏。

Spring Security配置:

    @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个答案

赖诚
2023-03-14

尽管接受了上述答案(感谢Praveen的帮助!),我找到的唯一真正的解决方案是避免Spring的默认注销-

注销处理程序只是一个常规控制器处理程序(我将其命名为“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; 
}

如果需要param,它在服务器端和客户端的注销JSP中都有:

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

所有以某种方式重定向到使用参数登录的建议——无论是使用这里的CustomLogoutSuccessHandler实现,还是直接通过这里的控制器重定向——在Spring Security Config“Login wall”需求为

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

在您的特殊权限列表之后。它不起作用,因为Spring Security将首先执行带有NO参数的基本 /login的Login-Wall要求,只要您尝试甚至重定向到带有参数的Login。并且只有这样,在您验证自己之后,它才会为带有参数的重定向服务,例如login?logout

我认为我们不应该在Config中去掉. enticated(),因为这是对所有请求创建Login-Wall保护的原因,这是一个重要的安全功能。但是当你有它时,你就不能将参数传递给/login,因为带有NO参数的基本Login-Wall/login总是会先发生。

这个问题没有真正的解决方案——我唯一能解决这个问题的方法就是绕过整个默认行为,只需要有一个与登录完全不同的专用注销页面。这个解决方案有效,我不需要立即重新显示登录页面。

梁丘扬
2023-03-14

您需要logoutAccessHandler而不是. logoutAccessUrl("/login? logout")
配置logoutAccessHandler如下所示

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

我考虑编写自己的/注销处理程序

事实上,这不是注销处理程序,但它是注销启动器。
使用CustomLogout成功处理程序,您可以在其中获取请求参数's,并且可以再次设置它,如下所示。

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 Logout URL(注销是自动的,所以我没有特定的处理程序)

servlet/Spring security中没有自动注销功能。只有我们能实现的是
1.自动化客户端发送注销请求
2.在服务器中我们可以设置session的maxInactiveInterval,这样就可以通过删除cookie/将cookie的年龄设置为过去的日期来使会话无效。一旦会话对下一个请求无效,Spring security过滤器链中的过滤器之一将其重定向到参数过期的 /login页面。/login? expated
如果您发起注销Spring security将删除cookie/使会话无效并重定向到参数注销的 /login页面。/login? logout
在Spring security中实现注销的配置有两种类型。

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

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

“登录墙”是坏*配置的结果,您将定义一个自定义登录页面,并将其配置为在身份验证后允许访问的资源。(access=isAuthenticated)但如果我们在会话无效后重定向到登录页面,则来自CustomLogoutSuccessHandler,Spring Security阻止登录页面访问(401未授权),因为该页面仅允许经过身份验证的用户访问。阻塞后,Spring Security性负责重定向到配置中配置的页面。登录页面(“/someloginpage”)。它迫使我们思考的是,正确地注销,正确地重定向到登录页面,但我在查询字符串中发送的参数并没有进入登录页面。如果我把这个叫做拼图,这没什么错,很难猜。

 类似资料:
  • 问题内容: 我想将值传递给javascript。如果可能的话,我该怎么办?如何在后备bean中接收它们? 问题答案:

  • 问题内容: 我们已经设置了一些参数来在Jenkins中执行构建(使用简单的“参数化构建”设置)。作业被设置为Maven测试。有没有办法以编程方式将这些参数传递到我们的Java代码中?我们需要基于通过Jenkins设置的参数来执行某些更新功能。 问题答案: 是的,您可以通过Maven执行将Jenkins参数传递给Java代码,如下所示: 请注意, $ JOB_PARAM_1 将捕获Jenkins上设

  • 当ARDUINO UNO上的引脚2接地时,此示例使用键盘库将您从计算机上的用户会话中注销。 草图同时按两个或三个键的顺序模拟按键,并在短暂延迟后释放它们。 Warning - 使用Keyboard.print()命令时,Arduino将接管计算机的键盘。 为确保在使用此功能运行草图时不会失去对计算机的控制,请在调用Keyboard.print()之前设置可靠的控制系统。 此草图设计为仅在将引脚拉到

  • 我正在为webste构建一个功能,用户可以在其中重置密码。他收到一封电子邮件,其中包含URL中生成的令牌。单击此链接时,用户将被发送到/Reset页面。该页的Get方法如下:

  • 我对JSP/servlets相当陌生,我一直在研究一些东西,它已经工作了一段时间。我有一个名为'telgir.jsp'的jsp,我从这个jsp向一个名为'tel Kayit'的servlet传递一个URL参数。 在LocalHost上运行时JSP页面的一个示例URL: 当我在servlet中接收到参数时,参数发生了变化,因此无法正确地对其进行解码并获得结果。根据我的研究,我意识到“%”符号使我的代

  • 问题内容: 我已经编写了这个jQuery ajax方法,在下面调用了webmethod。除了作为用户对象的参数具有空字段之外,调用进行得很好。我在调试时可以在firebug中看到值,但它们无法通过webmethod中的User对象参数 我试图从jQuery方法传递给Webmethod的两个值是“ UserID”(Guid)和“ About”(字符串),它们都是User类的属性,但在服务端,是Use