【每日进步一点点】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",

调用代码为:

<a th:href="@{/logout}">退出</a>

问题:点击后根本无法注销,浏览器报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的配置没有什么关系了。

例如,调用修改为:

<a th:href="@{/mylogout}">退出</a>

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方法,而我们使用的是<a href>这种方式,这个方式是GET方法,这个就是问题的关键所在。

 知道问题所在后,我觉得采用ajax发送post消息来验证,代码如下:

<a  onclick="exit();">退出</a>


<script>
        
        function exit() {           
            $.ajax({
                type: "post",
                async: false,
                url: basePath + "/logout",
                success: function (res) {                    
                }
            });
        }
</script>

  嗯,这样的确可以退出成功,但 .logoutSuccessUrl("/login.html"); 这个配置不生效。

  看了源代码,主要是redirectStrategy.sendRedirect 不生效。

  百度搜了一下,用ajax调用时,无法更新整个页面,所以这个是无效的。

  当然还是有办法处理的。

  在ajax调用成功后,success方法中网页重新定向到/login.html就可以了。

  代码如下:  

<a  onclick="exit();">退出</a>


<script>
        
        function exit() {           
            $.ajax({
                type: "post",
                async: false,
                url: basePath + "/logout",
                success: function (res) {
                     window.location.href = "/login.html";
                }
            });
        }
</script>

 以上也实现了整个功能,但有缺憾,登录成功后的跳转路径不生效。

 

解决方案三:正规解决办法

以上两个方案都实现了登录退出的功能,但SpringSecurity的配置都有些不生效,说明这个和SpringSecurity配置的

初衷还是不一样的,因此思考后,认为还是应该用form的正规方式来处理,因此正规解决办法如下:

网页调用端代码:

<li class="layui-nav-item">
            <form th:action="@{/logout}" method="post">
                <input id="exit" type="submit" value="退出">
            </form>
</li>

<style type="text/css">
        #exit {
            background-color: #000000;
            color: #ffffff;
            border: 0px;

            margin-left: 15px;
            margin-right: 15px;
        }
</style>

  用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

 一切都很完美!

 

 

 

  

 

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
### 回答1: Spring Security退出登录可以通过以下步骤实现: 1. 在Spring Security配置文件中添加logout配置: ``` http.logout() .logoutUrl("/logout") .logoutSuccessUrl("/login") .invalidateHttpSession(true) .deleteCookies("JSESSIONID"); ``` 2. 在Web应用程序中添加一个处理/logout请求的控制器: ``` @Controller public class LogoutController { @RequestMapping(value="/logout", method = RequestMethod.GET) public String logoutPage (HttpServletRequest request, HttpServletResponse response) { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth != null){ new SecurityContextLogoutHandler().logout(request, response, auth); } return "redirect:/login?logout"; } } ``` 3. 在Web应用程序中添加一个退出登录的链接或按钮,链接到/logout请求: ``` <a href="/logout">退出登录</a> ``` 当用户点击退出登录链接或按钮,将调用/logout请求,Spring Security将清除用户的身份验证信息并重定向到登录页面。 ### 回答2: Spring Security是一个强大而灵活的安全框架,它可以实现用户管理、认证授权、角色控制等安全功能。在一个Spring应用程序中,我们经常需要为用户提供退出登录的功能,这是保障用户安全的重要措施。在Spring Security中,实现退出登录的方法有以下几种: 1.使用Spring Security提供的logout()方法 Spring Security提供了logout()方法,可以使用户退出登录。可以在Spring Security的配置类里面添加这个方法指定退出登录的URL地址和成功退出登录后的跳转地址: ``` @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .logout() .logoutSuccessUrl("/login") // 退出成功后跳转地址 .logoutUrl("/logout"); // 退出请求的URL } } ``` 2.使用Spring MVC的Controller 如果应用程序中使用了Spring MVC,那么我们也可以使用Spring MVC的Controller来实现退出登录功能。可以在Controller里面添加一个映射方法来处理退出登录请求,重定向到登录页面: ``` @Controller public class LogoutController { @GetMapping("/logout") public String logout(HttpServletRequest request) { // 手动注销当前用户 SecurityContextHolder.getContext().setAuthentication(null); // 重定向到登录页面 return "redirect:/login"; } } ``` 3.使用JavaScript实现退出登录 最后一种方法是使用JavaScript来实现退出登录功能。我们可以在页面上添加一个退出登录的按钮,当用户点击按钮,通过JavaScript代码发送请求来实现退出登录: ``` $('#logout').click(function() { $.post("/logout", function() { window.location.href = "/login"; }); }); ``` 以上三种方法中,第一种方法使用了Spring Security提供的logout()方法来实现退出登录,最为简单快捷;第二种方法使用Spring MVC的Controller来实现退出登录,比较灵活;第三种方法使用JavaScript实现退出登录,可以在前端页面上实现交互。可以根据实际情况选择合适的方法来实现退出登录功能。 ### 回答3: 在Spring Security中,退出登录是一个常见的功能,可以让用户在不需要再次登录的情况下退出应用程序。Spring Security提供了两个默认退出登录的方式:通过URL和通过表单。以下是关于这两种方式的介绍。 通过URL退出登录 通过URL退出登录是最简单的方式。用户可以访问一个指定的URL(通常是/logout)以退出登录Spring Security将会清除已登录的用户的安全上下文,并跳转至指定的URL(通常是登录页面)。 例如,在Spring Boot应用程序中,可以通过添加以下配置来启用URL退出登录: ``` @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .formLogin() .and() .logout() // 开启退出登录支持 .logoutUrl("/my/logout") // 自定义退出登录的URL地址 .logoutSuccessUrl("/my/index") // 退出登录后跳转的URL地址 .invalidateHttpSession(true) // 清除session .deleteCookies("JSESSIONID") // 删除cookie .permitAll(); } } ``` 相应地,在页面中,可以通过一个超链接或者一个button来触发退出登录操作: ``` <a href="/my/logout">退出登录</a> <button onclick="location.href='/my/logout'">退出登录</button> ``` 通过表单退出登录 通过表单退出登录需要创建一个HTML表单,并将其提交到指定的URL(通常是/logout)。该表单需要包含一个隐藏字段(CSRF)和一个提交按钮。Spring Security将检测这个表单,并告诉Spring Security配置的LogoutHandler和LogoutSuccessHandler执行退出登录操作。 例如,一个简单的表单可能看起来像这样: ``` <form th:action="@{/logout}" method="post"> <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" /> <button type="submit">退出登录</button> </form> ``` 在Spring Boot应用程序中,可以通过添加以下配置来启用表单退出登录: ``` @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .formLogin() .and() .logout() // 开启退出登录支持 .logoutUrl("/my/logout") // 自定义退出登录的URL地址 .logoutSuccessUrl("/my/index") // 退出登录后跳转的URL地址 .invalidateHttpSession(true) // 清除session .deleteCookies("JSESSIONID") // 删除cookie .permitAll() .csrf() // 开启CSRF保护 .csrfTokenRepository(csrfTokenRepository()) // 自定义CSRF令牌的实现 .and() .addFilterAfter(csrfFilter(), CsrfFilter.class); // 添加到CSRF过滤器之后 } private CsrfTokenRepository csrfTokenRepository() { HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository(); repository.setHeaderName("X-CSRF-TOKEN"); return repository; } private Filter csrfFilter() { return new OncePerRequestFilter() { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { CsrfToken csrfToken = (CsrfToken) request.getAttribute(CsrfToken.class.getName()); if (csrfToken != null) { Cookie cookie = new Cookie("XSRF-TOKEN", csrfToken.getToken()); cookie.setPath("/"); response.addCookie(cookie); } filterChain.doFilter(request, response); } }; } } ``` 需要注意,该表单必须包含CSRF令牌。如果没有包含,Spring Security将拒绝退出登录请求。 总结 Spring Security退出登录是一个常见的功能,可以通过URL和表单两种方式来实现。其中,URL退出登录更简单,而表单退出登录需要更多的配置。在实现退出登录,还需要注意安全性问题,如CSRF保护。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

灰暗角落里的琴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值