java - Spring Security,注销:将参数从 /logout 传递到 /login
问题描述
我正在使用默认的 Spring Security 来处理注销/登录。我有一个控制器方法来处理/login
.
当我注销时,我看到 Spring Security 将我重定向到app/login?logout
. 这个 Spring-created 参数的存在(有时也存在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 Logout URL(注销是自动的,所以我没有特定的处理程序):
myapp.com/app/logout?exitMsg=MyMessage
马上,登录处理程序丢失了这个参数,而我没有它。
我考虑编写自己的/logout
处理程序,在其中手动注销(使会话无效),然后使用此参数重定向到自己登录。这是这里的建议。但如果我这样做,我将失去获取 Spring 的自动 ?logout
和?error
请求参数的能力。在自动场景中,我得到了它们,现在我没有。我只得到我自己指定的自定义参数。我需要保留?logout
并?error
测试我自己的新参数。
任何想法高度赞赏。
弹簧安全配置:
@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");
}
我考虑编写自己的 /logout 处理程序
实际上,这不是注销处理程序,而是注销发起程序。
使用 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");
}
}
}
从我的应用程序中,我发出这个 Spring Security Logout URL(注销是自动的,所以我没有特定的处理程序)
servlet/spring security 中没有自动注销功能。只有我们能实现的是
1. 自动化客户端发送注销请求
2. 在服务器中我们可以设置会话的 maxInactiveInterval,这样可以通过删除 cookie/设置 cookie 的年龄到过去的日期来使会话失效。一旦会话因下一个请求而失效,spring 安全过滤器链中的过滤器之一会将其重定向到参数已过期的 /login 页面。/login?expired
如果您启动注销,spring security 将删除 cookie/使会话无效并使用参数注销重定向到 /login 页面。/login?logout
spring security中实现注销的配置有两种。
.and().logout()
.invalidateHttpSession(true)
//or
.deleteCookies("JSESSIONID")
编辑:看到OP的答案后。缺少信息在此处添加。OP 和我在临时答案中进行了长时间的聊天(该聊天和答案已被删除),我们在其中找到了LOGIN-WALL。
“登录墙”是 bad* 配置的结果,您将在其中定义自定义登录页面,并将其配置为允许在身份验证后访问的资源。( access=isAuthenticated
) 但来自 CustomLogoutSuccessHandler 如果我们在使会话弹簧安全阻止登录页面访问(401-Un Authorized)无效后重定向到登录页面,因为该页面仅允许经过身份验证的用户使用。在阻塞 spring security 之后,会处理重定向到配置中配置的页面。`.loginPage("/someloginpage")。它强制认为是注销发生正确,正确重定向到登录页面,但我在查询字符串中发送的参数没有进入登录页面。
如果我把这称为很难猜到的谜题,那也没什么错。
推荐阅读
- python - Windows 上的 IPython 无法导入 geopandas
- swift - 使用出队的 dequeueReusableCell - 出队后单元格的 textField
- javascript - 如何在Javascript中获取不包含在另一个数组中的数组项
- linux - 如何打印一些linux进程的命令行
- function - PyQt5 多个按钮和 1 个函数来更改按钮文本
- android - 使用颤振小部件测试测试接收意图
- javascript - 为什么节点找不到 SubmitEvent?
- java - 为什么(字符串)切换案例在 JSP 中不起作用
- python - 使用新列名将 Pandas 中的数据框从长格式改写为宽格式
- asp.net-core - Blazor 布局未呈现