我使用默认的Security来处理注销/登录。我有一个控制器方法来处理/login。
当我注销时,我看到Security将我重定向到app/login?logout。这个Spring创建的参数(有时还包括app/login?error)的存在允许我将我的Login处理程序编写为:
@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,就像系统创建的error和logout一样,我可以检查它。
假设这个自定义参数是exitMsg。
在我的应用程序中,我发布了这个(注销是自动的,因此我没有特定的处理程序):
myapp.com/app/logout?exitMsg=MyMessage
马上,Login处理程序就会失去这个param,而我没有它。
我考虑编写自己的/logout处理程序,手动注销(使会话无效),然后用这个param重定向到Login本人。这是建议here。但是如果这样做,就失去了获得Spring的自动 ?logout和?error请求参数的能力。在自动的场景中,我得到了它们,现在我没有了。我只得到我自己指定的自定义参数。我需要保留?logout和?error,并测试我自己的新param。
任何想法都值得高度赞赏。
弹簧安全控制:
@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();
}发布于 2019-09-26 12:43:57
您需要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,您可以获得请求param,并且可以重新设置它,如下所示。
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安全中没有自动注销功能。只有我们能实现的是
/login?expired。如果启动注销,spring安全性将删除cookie/使会话无效,并使用param注销./login?logout重定向到/login?logout页面。
实现spring安全注销的配置有两种。。
.and().logout()
.invalidateHttpSession(true)
//or
.deleteCookies("JSESSIONID")编辑:在看到OP的答案之后。缺少的信息添加在这里。OP和我在临时应答中进行了长时间的聊天(这个聊天和回答已经被删除了),在这里我们找到了登录名-WALL。
“登录墙”是坏*配置的结果,您将定义一个自定义登录页面,并将其配置为允许身份验证后访问的资源。(access=isAuthenticated)但是从CustomLogoutSuccessHandler,如果我们重定向到登录页面后,会话春季安全阻止登录页面访问(401-un授权),因为该页面只允许通过身份验证的用户。阻塞spring后,安全性负责重定向到配置中配置的页面。`.loginPage("/someloginpage")。它强制认为正确地进行注销,正确地重定向到登录页面,但我在查询字符串中发送的params并没有进入loginpage。没有错,如果我称之为谜题,这是很难猜测的。
发布于 2019-09-27 01:17:29
尽管接受了上面的答案(感谢Praveen的帮助!),我找到的唯一真正的解决方案是避免Spring的默认注销->登录行为,并使用带有新的专用Logout的自定义Logout处理程序,这不是Login页面。因此,我避免了重定向到登录页面,我只是有一个单独的登录页面--它们已经不一样了。如果用户想再次登录,那么他们可以键入URL /app/login来登录。
Logout处理程序只是一个常规控制器处理程序(我将其命名为"myLogout"),
@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中的服务器端和客户端都有:
`${param.exitMsg}`: --> Output: `test`. 所有以某种方式重定向到带有参数的登录的建议--无论是使用CustomLogoutSuccessHandler实现(如here )还是直接通过控制器重定向(如here ) --当您有Security“登录墙”要求时,所有建议都不起作用。
// ... special URLs listed here, then at the end:
.antMatchers("/participant/**").authenticated()在您的特殊权限列表之后。它不起作用,因为Security将完成的登录墙要求,这是一个没有参数的基本/login,只要您尝试重定向到带有参数的登录,就会立即开始。只有在您验证了自己之后,它才会为重定向参数(如login?logout&exitMsg=... )提供服务。你想要的。换句话说,你仍然会失去你的第一个登录墙要求的参数,因为你已经注销了。
我不认为我们应该摆脱Config中的.authenticated(),因为这就是对所有请求创建登录墙保护的原因,这是一个重要的安全功能。但是,当您拥有它时,您就不能将参数传递给/login,因为带有的基本登录墙/login (无参数)总是首先发生的。
对于这个问题,没有真正的解决方案--我唯一解决的方法就是绕过整个默认行为,只拥有一个与Login完全不同的专用注销页面。此解决方案有效,我不需要立即重新显示登录页面。
https://stackoverflow.com/questions/58108549
复制相似问题