【每日进步一点点】SpringSecurity退出登录不生效问题

SpringSecurity实现了登录,但配置了退出登录,始终不成功。

配置情况如下:

@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实现

我们自定义了一个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

我们都知道,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

     一切都很完美!

     

     

     

      

     

    你可能感兴趣的:(每日进步一点点,springsecurity)