java - Spring安全,注销: Pass parameter from/logout to/login

标签 java spring spring-boot spring-mvc spring-security

我使用默认的 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 注销 URL(注销是自动的,因此我没有特定的处理程序):

myapp.com/app/logout?exitMsg=MyMessage

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

我考虑编写自己的 /logout 处理程序,在其中手动注销(使 session 无效),然后使用此参数重定向到我自己登录。这是建议here 。但如果我这样做,我将失去获取 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();
    }

最佳答案

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

I considered writing my own /logout handler

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

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

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

.and().logout()
.invalidateHttpSession(true)
//or
.deleteCookies("JSESSIONID")
<小时/>

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

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

关于java - Spring安全,注销: Pass parameter from/logout to/login,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58108549/

相关文章:

java - 如何知道已经建立的连接的状态?

java - 加载后立即显示 AdMob 插页式广告

Hibernate/JPA @AttributeOverrides 与 Groovy 不能很好地配合

java - 如何在Spring boot中的每个请求中添加具有静态值的特定 header ?

docker - Spring Boot,Docker,Discovery eureka

java - 安排固定费率拒绝工作

java - 优化多个 Java 数组添加

java - 使用 @Import 时未创建 Bean

java - 禁用 Spring Security 的 POST 方法

java - 用于多个数据库连接的 Flyway (Java/Spring)