我使用默认的 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
中接收一个参数,我可以像系统创建的 error
和 logout
一样检查它。
假设这个自定义参数是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/