配置情况如下:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/css/**").permitAll()
.anyRequest().authenticated() //任何未匹配的URL都要进行身份验证
.and()
.formLogin()
.loginPage("/login.html")
.failureUrl("/login-error.html").permitAll()
.defaultSuccessUrl("/home.html")
.and()
.logout()
.logoutUrl("/logout") //注销URL
.logoutSuccessUrl("/login.html");
}
其中配置了logoutUrl为"/logout",
调用代码为:
退出
问题:点击后根本无法注销,浏览器报404,即无法找到http://localhost:8080/logout。
我们自定义了一个logout方法,实现了退出登录,如下:
@RequestMapping(value="/logout")
public String logoutPage (HttpServletRequest request, HttpServletResponse response) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null){
new SecurityContextLogoutHandler().logout(request, response, auth);
}
return "redirect:/login.html";
}
评述:该解决办法还是不错,能够达到效果,但跟springsecurity的配置没有什么关系了。
例如,调用修改为:
退出
mylogout实现如下:
@RequestMapping(value="/mylogout")
public String logoutPage (HttpServletRequest request, HttpServletResponse response) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null){
new SecurityContextLogoutHandler().logout(request, response, auth);
}
return "redirect:/login.html";
}
一样可以成功,就说明和SpringSecurity的配置项没有关系了。
我们都知道,SpringSecurity本身有LogoutFilter这个filter,专门处理退出登录用的。
我们看一下LogoutFilter.java中doFilter的源代码
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if (requiresLogout(request, response)) { //这里进行验证
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (logger.isDebugEnabled()) {
logger.debug("Logging out user '" + auth
+ "' and transferring to logout destination");
}
this.handler.logout(request, response, auth);
logoutSuccessHandler.onLogoutSuccess(request, response, auth);
return;
}
chain.doFilter(request, response);
}
进行源代码跟踪,发现在requiresLogout(request, response) 中未通过,继续深入match,
@Override
public boolean matches(HttpServletRequest request) {
if (this.httpMethod != null && StringUtils.hasText(request.getMethod())
&& this.httpMethod != valueOf(request.getMethod())) {
...
return false;
}
...
}
这里第一个验证就是调用方法的验证,跟踪发现:
/logout要求是POST方法,而我们使用的是这种方式,这个方式是GET方法,这个就是问题的关键所在。
知道问题所在后,我觉得采用ajax发送post消息来验证,代码如下:
退出
嗯,这样的确可以退出成功,但 .logoutSuccessUrl("/login.html"); 这个配置不生效。
看了源代码,主要是redirectStrategy.sendRedirect 不生效。
百度搜了一下,用ajax调用时,无法更新整个页面,所以这个是无效的。
当然还是有办法处理的。
在ajax调用成功后,success方法中网页重新定向到/login.html就可以了。
代码如下:
退出
以上也实现了整个功能,但有缺憾,登录成功后的跳转路径不生效。
以上两个方案都实现了登录退出的功能,但SpringSecurity的配置都有些不生效,说明这个和SpringSecurity配置的
初衷还是不一样的,因此思考后,认为还是应该用form的正规方式来处理,因此正规解决办法如下:
网页调用端代码:
用submit按钮来实现,为了和原有代码显示一致,使用了#exit样式进行配置。
SpringSecurity的Config配置如下(和前面的没有变化,这里只是拿出来统一展示):
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/css/**").permitAll()
.anyRequest().authenticated() //任何未匹配的URL都要进行身份验证
.and()
.formLogin()
.loginPage("/login.html")
.failureUrl("/login-error.html").permitAll()
.defaultSuccessUrl("/home.html")
.and()
.logout()
.logoutUrl("/logout") //注销URL
.logoutSuccessUrl("/login.html");
}
OK,现在可以只需点击“退出”这个Submit按钮,其余的都按照SpringSecurity的配置进行了。
登录退出 /logout
登录成功转向页面 /login.html
一切都很完美!