Spring Security,注销:将参数从/logout 传递到/login [英] Spring Security, Logout: Pass parameter from /logout to /login

查看:67
本文介绍了Spring Security,注销:将参数从/logout 传递到/login的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

当我注销时,我看到 Spring Security 将我重定向到 app/login?logout.这个 Spring 创建的参数(有时还有 app/login?error)的存在允许我将我的登录处理程序编写为:

@GetMapping("/参与者/登录")公共 ModelAndView loginPage(HttpServletRequest 请求,HttpServletResponse 响应,@RequestParam(value = "error", required = false) 字符串错误,@RequestParam(value = "logout", required = false) String logout) {log.info("进入参会者登录页面");ModelAndView mav = new ModelAndView(LOGIN_JSP);如果(空!= 错误){//我们在错误后进入登录页面mav.addObject("info", "我的通用错误信息");} else if(null !=注销){//我们在注销后进入登录页面mav.addObject("info", "我的通用注销消息");}//...否则,正常登录页面,没有额外信息

现在的问题是,当我注销时,我需要将自定义参数传递给/logout 并传输到/login.目标是我需要在 /login 中接收一个参数,我可以像系统创建的 errorlogout 一样检查它.

假设这个自定义参数是exitMsg.

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

myapp.com/app/logout?exitMsg=MyMessage

立即,登录处理程序丢失了这个参数,而我没有.

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

高度赞赏任何想法.

Spring 安全配置:

 @Overrideprotected void configure(HttpSecurity http) 抛出异常 {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("/参与者/登录").permitAll().failureUrl("/participant/login?error").permitAll().defaultSuccessUrl("/参与者/家").usernameParameter("用户名").passwordParameter("密码").and().logout().logoutUrl("/参与者/注销").logoutSuccessUrl("/participant/login?logout").permitAll().and().csrf().disable();}

解决方案

你需要 logoutSuccessHandler 而不是 .logoutSuccessUrl("/login?logout")
配置 logoutSuccessHandler 如下

@Overrideprotected void configure(final HttpSecurity http) 抛出异常{http.authorizeRequests().antMatchers("/resources/**", "/", "/login", "/api/**").permitAll().antMatchers("/app/admin/*").hasRole("管理员").antMatchers("/app/user/*").hasAnyRole("管理员","用户").and().exceptionHandling().accessDeniedPage("/403").and().formLogin().loginPage("/login").usernameParameter("userName").passwordParameter("密码").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;导入 javax.servlet.ServletException;导入 javax.servlet.http.Cookie;导入 javax.servlet.http.HttpServletRequest;导入 javax.servlet.http.HttpServletResponse;导入 org.springframework.security.core.Authentication;导入 org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;公共类 CustomLogoutSuccessHandler 扩展 SimpleUrlLogoutSuccessHandler{@覆盖public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) 抛出 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");}别的{response.sendRedirect(request.getContextPath() + "/login?logout=true");}}}

<块引用>

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

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

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

<小时>

在看到 OP 的回答之后.在此处添加缺少的信息.OP 和我在临时回答中进行了长时间聊天(该聊天和回答已被删除),我们在那里找到了 LOGIN-WALL.

登录墙"是错误*配置的结果,您将在其中定义自定义登录页面,并将其配置为在身份验证后允许访问的资源.(access=isAuthenticated) 但来自 CustomLogoutSuccessHandler 如果我们在会话无效后重定向到登录页面 spring 安全阻止登录页面访问(401-Un 授权),因为该页面仅允许经过身份验证的用户使用.阻止后,spring security 负责重定向到配置中配置的页面.`.loginPage("/someloginpage").它强制认为注销正确发生,正确重定向到登录页面,但我在查询字符串中发送的参数没有进入登录页面.如果我将其称为非常难以猜测的谜题也没有错.

I'm using default Spring Security to handle logout/login. I have a Controller method that handles /login.

When I log out, I see that Spring Security redirects me to app/login?logout. The existence of this Spring-created parameter (and also sometimes app/login?error) allows me to write my Login handler as:

@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

Now the problem is that when I log out, I need to pass a custom parameter to /logout with a transfer to /login. The goal is I need to receive a param in /login that I can examine just like the system-created error and logout.

Suppose this custom param is exitMsg.

From my app I issue this Spring Security Logout URL (logout is automatic, so I don't have a specific handler for it):

myapp.com/app/logout?exitMsg=MyMessage

Right away, the Login handler loses this param and I don't have it.

I considered writing my own /logout handler, where I manually log out (invalidate the session), and then redirect to Login myself with this param. This is the suggestion here. But if I do that, I lose the ability to get Spring's automatic ?logout and ?error Request Params. In the automatic scenario I was getting them, and now I'm not. I'm only getting the custom parameter I specify myself. I need to keep ?logout and ?error and also test for my own new param.

Any thoughts highly appreciated.

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

解决方案

You need logoutSuccessHandler instead of .logoutSuccessUrl("/login?logout")
Configure logoutSuccessHandler as given below

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

I considered writing my own /logout handler

In fact that is not logout handler but it is logout initiator.
Use CustomLogoutSuccessHandler, where you can get request param's and you can set it again, as given below.

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

From my app I issue this Spring Security Logout URL (logout is automatic, so I don't have a specific handler for it)

There is no automatic logout feature in servlet/spring security. Only what we can achieve is
1. Automate client to send logout request
2. In server we can set session's maxInactiveInterval, so that session can be invalidated by deleting cookie/setting age of cookie to past date. Once session is invalidated for the next request one of filter in spring security filter chain redirects it to /login page with param expired./login?expired
If you initiates logout spring security will delete the cookie/invalidate the session and redirects to /login page with param logout./login?logout
There are two types of configuration of achieving logout in spring security.

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


EDIT: After Seeing OP's Answer. Missing info adding here. OP and i had a long chat in temporary answer(That chat and answer has been deleted) where we found the LOGIN-WALL.

"login-wall" is a outcome of bad* configuration where you will define a custom login page and it is configured as resource that is allowed to access after authentication. (access=isAuthenticated) but from CustomLogoutSuccessHandler if we redirect to login page after invalidating session spring security blocks login page access(401-Un Authorized) since that page is allowed only for authenticated-user. After blocking spring security takes care of redirects to the page configured in configuration. `.loginPage("/someloginpage"). What it forces to think is logout happening correctly, redirecting to login page correctly but params i sent in query string are not coming to loginpage. Nothing wrong if i call this as puzzle which is very hard to guess.

这篇关于Spring Security,注销:将参数从/logout 传递到/login的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆