首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Security,Logout:将参数从/logout传递给/login

Security,Logout:将参数从/logout传递给/login
EN

Stack Overflow用户
提问于 2019-09-26 01:55:53
回答 2查看 3.7K关注 0票数 3

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

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

代码语言:javascript
复制
@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中接收一个param,就像系统创建的errorlogout一样,我可以检查它。

假设这个自定义参数是exitMsg

在我的应用程序中,我发布了这个(注销是自动的,因此我没有特定的处理程序):

myapp.com/app/logout?exitMsg=MyMessage

马上,Login处理程序就会失去这个param,而我没有它。

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

任何想法都值得高度赞赏。

弹簧安全控制:

代码语言:javascript
复制
    @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();
    }
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-09-26 12:43:57

您需要logoutSuccessHandler而不是.logoutSuccessUrl("/login?logout")

配置logoutSuccessHandler,如下所示

代码语言:javascript
复制
@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,您可以获得请求param,并且可以重新设置它,如下所示。

代码语言:javascript
复制
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");
        }
    }
}

来自我的应用程序的

我发布了这个Security (注销是自动的,所以我没有一个特定的处理程序)

servlet/spring安全中没有自动注销功能。只有我们能实现的是

  1. 自动化客户端在服务器端发送注销请求
  2. ,我们可以设置会话的maxInactiveInterval,这样会话就可以通过删除cookie /cookie的设置时间到过去的日期而失效。一旦会话对下一个请求无效,spring安全筛选链中的一个筛选器将其重定向到/login页,并已过期./login?expired

如果启动注销,spring安全性将删除cookie/使会话无效,并使用param注销./login?logout重定向到/login?logout页面。

实现spring安全注销的配置有两种。。

代码语言:javascript
复制
.and().logout()
.invalidateHttpSession(true)
//or
.deleteCookies("JSESSIONID")

编辑:在看到OP的答案之后。缺少的信息添加在这里。OP和我在临时应答中进行了长时间的聊天(这个聊天和回答已经被删除了),在这里我们找到了登录名-WALL

“登录墙”是坏*配置的结果,您将定义一个自定义登录页面,并将其配置为允许身份验证后访问的资源。(access=isAuthenticated)但是从CustomLogoutSuccessHandler,如果我们重定向到登录页面后,会话春季安全阻止登录页面访问(401-un授权),因为该页面只允许通过身份验证的用户。阻塞spring后,安全性负责重定向到配置中配置的页面。`.loginPage("/someloginpage")。它强制认为正确地进行注销,正确地重定向到登录页面,但我在查询字符串中发送的params并没有进入loginpage。没有错,如果我称之为谜题,这是很难猜测的

票数 1
EN

Stack Overflow用户

发布于 2019-09-27 01:17:29

尽管接受了上面的答案(感谢Praveen的帮助!),我找到的唯一真正的解决方案是避免Spring的默认注销->登录行为,并使用带有新的专用Logout的自定义Logout处理程序,这不是Login页面。因此,我避免了重定向到登录页面,我只是有一个单独的登录页面--它们已经不一样了。如果用户想再次登录,那么他们可以键入URL /app/login来登录。

Logout处理程序只是一个常规控制器处理程序(我将其命名为"myLogout"),

代码语言:javascript
复制
@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,那么它在Logout JSP中的服务器端和客户端都有:

代码语言:javascript
复制
     `${param.exitMsg}`:  --> Output: `test`. 

所有以某种方式重定向到带有参数的登录的建议--无论是使用CustomLogoutSuccessHandler实现(如here )还是直接通过控制器重定向(如here ) --当您有Security“登录墙”要求时,所有建议都不起作用。

代码语言:javascript
复制
    // ... special URLs listed here, then at the end:
    .antMatchers("/participant/**").authenticated()

在您的特殊权限列表之后。它不起作用,因为Security将完成的登录墙要求,这是一个没有参数的基本/login,只要您尝试重定向到带有参数的登录,就会立即开始。只有在您验证了自己之后,它才会为重定向参数(如login?logout&exitMsg=... )提供服务。你想要的。换句话说,你仍然会失去你的第一个登录墙要求的参数,因为你已经注销了。

我不认为我们应该摆脱Config中的.authenticated(),因为这就是对所有请求创建登录墙保护的原因,这是一个重要的安全功能。但是,当您拥有它时,您就不能将参数传递给/login,因为带有的基本登录墙/login (无参数)总是首先发生的。

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58108549

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档