1、问题:使用springboot整合springsecurity做登录时,使用自定义退出登录,在使用LogoutHandler处理退出登录逻辑时authentication为空,代码如下:

import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutHandler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author lisuo
 * @version 1.0
 * @Description
 * @email 495019733@qq.com
 * @date 2021/12/26 17:36
 */
@Slf4j
public class UserLogoutHandler implements LogoutHandler {
    @Override
    public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
        String username = (String) authentication.getPrincipal();
        log.info("username: {}  is offline now", username);
    }
}

在security配置中配置登录退出逻辑处理

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and()
                .csrf()
                .disable()
                .authorizeRequests()
                // 测试用资源,需要验证了的用户才能访问
                .antMatchers("/tasks/**").authenticated()
                // 其他都放行了
                // 登录
                .and()
                .formLogin()
                .and().logout().addLogoutHandler(new UserLogoutHandler()).logoutSuccessHandler(new UserLogoutSuccessHandler())
                .and()

                .addFilter(new JwtAuthenticationFilter(authenticationManager()))
                .addFilter(new JwtAuthorizationFilter(authenticationManager()))
                // 不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .exceptionHandling().authenticationEntryPoint(new JwtAuthenticationEntryPoint())
                //添加无权限时的处理
                .accessDeniedHandler(new JwtAccessDeniedHandler());
    }

2、原因:问题出在了LogoutFilter拦截器,LogoutFilter在我自定义JwtAuthorizationFilter之前拦截了请求,在默认的LogoutFilter中并没有对token进行解析并设置SecurityContextHolder中设置认证信息上下文,所以导致LogoutHandler中获取到的authentication为null。

3、解决方案:LogoutFilter拦截器之前校验token设置SecurityContextHolder上下文,这个可以在配置中配置

.addFilterBefore(new JwtAuthorizationFilter(authenticationManager()), LogoutFilter.class)

具体代码如下:

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and()
                .csrf()
                .disable()
                .authorizeRequests()
                // 测试用资源,需要验证了的用户才能访问
                .antMatchers("/tasks/**").authenticated()
                // 其他都放行了
                // 登录
                .and()
                .formLogin()
                .and().logout().addLogoutHandler(new UserLogoutHandler()).logoutSuccessHandler(new UserLogoutSuccessHandler())
                .and()
                .addFilterBefore(new JwtAuthorizationFilter(authenticationManager()), LogoutFilter.class)
                .addFilter(new JwtAuthenticationFilter(authenticationManager()))
                .addFilter(new JwtAuthorizationFilter(authenticationManager()))
                // 不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .exceptionHandling().authenticationEntryPoint(new JwtAuthenticationEntryPoint())
                //添加无权限时的处理
                .accessDeniedHandler(new JwtAccessDeniedHandler());
    }

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐