这里对没有获取到token数据时为什么要放行的原因进行一个个人理解体会的记录 。
从 2.1、过滤器链 中的解释我们可以看到主要作用的有三个过滤器(图片已经贴到这里),其中可以简单的理解为第一个用于登录的、第二个用于异常捕获的、第三个则是从 SecurityContextHolder 中获取数据来鉴权 。
这时我们应该可以大致的感受出来为什么可以放行而不是抛异常了, 放行是为了可能需要后面的登录操作,不用担心有老六偷溜绕过认证是因为有第三个过滤器的存在。
因为如果是已登录的状态会在上面 自定义的过滤器 中将用户信息(内包含鉴权信息)存放至 SecurityContextHolder 中去,如果在该过滤器中没能成功从中拿到数据,那就证明该用户这次操作并不是登录操作,而是真正需要拦截的老六操作,因此就会在 FilterSecurityInterceptor过滤器 中抛出异常 。
而加上 return 的目的是为了避免在过滤器链往回执行的时候执行自定义过滤器中的后面逻辑,因为这是无用操作 。

文章插图
到这里其实还没有结束,因为我们还需要将自定义过滤器添加到过滤器链中,更准确的说是将自定义过滤器添加至
UsernamePasswordAuthenticationFilter过滤器的前面 ,当然这一操作Spring Security帮我们封装好了对应的方法,要不然要这框架有何用!
- 我们直接在 SecurityConfig配置类 中将自定义过滤器注入,并在 configure方法 中将其插入到指定位置 。
- 为了突出修改的地方,这里将部分前面已经配置的方法进行了隐藏去除 。
@Configurationpublic class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate JwtAuthenticationTokenFilter authenticationTokenFilter;/*** 配置SpringSecurity对需要放行的接口放行**/@Overrideprotected void configure(HttpSecurity http) throws Exception {http//关闭csrf.csrf().disable()//不通过Session获取SecurityContext.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()// 对于登录接口 允许匿名访问,其中的antMatchers可以传递一个数组.antMatchers("/user/login").anonymous()// 除上面外的所有请求全部需要鉴权认证.anyRequest().authenticated();// 参数列表分别为需要插入的过滤器和标识过滤器的字节码http.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);}}3.4.3、试当老六首先我们在不登录的情况下访问 /hello 接口,可以发现是访问不了的
文章插图
然后我们再尝试一下登录生成token,将token数据加入到请求头中之后再进行访问 。(token错误的我就不演示了哈,感兴趣的小伙伴自己可以测试一下)

文章插图
3.5、退出登录既然登录都搞了,登出怎么说也得来一手搞一条龙服务对吧 。
主要步骤如下:
- 从SecurityContextHolder中获取认证信息 。因为在访问退出接口的时候,肯定是已经登录了且是经过了自定义的过滤器,因此在SecurityContextHolder中是已经存放了该登录用户的基本数据信息,这样我们就是可以获取得到的 。
- 根据获取到的用户数据获取useId进行key的拼接,并从Redis中删除指定key的值,即删除该用户已登录的标识
@Servicepublic class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {@Autowiredprivate RedisCache redisCache;@Overridepublic Result<String> logout() {// 从SecurityContextHolder中获取认证信息Authentication authentication = SecurityContextHolder.getContext().getAuthentication();// 判空,避免登录已过期导致异常if (ObjectUtils.isEmpty(authentication)) {return Result.fail("登录已过期,退出登录失败");}// 从认证信息中获取登录用户数据LoginUser loginUser = (LoginUser) authentication.getPrincipal();// 从登录用户数据中获取userIdLong userId = loginUser.getUser().getId();// 从redis中将该用户的值删除redisCache.deleteObject("login:" + userId);return Result.success("退出登录成功");}}4、见证奇迹到这里其实就已经是这一条龙服务已经搞完啦,当我们去测试的时候可以完整的看到从登录到退出都是可以正常运行的,下面就是奇迹的时刻,居然没有bug!- 使用账号密码访问 /user/login 进行登录
推荐阅读
- SpringBoot集成MyBatis的相关要点
- 一文搞懂响应式编程
- SpringBoot 整合 Elasticsearch 实现海量级数据搜索
- SpringBoot接口 - 如何生成接口文档之Swagger技术栈?
- windows基于nginx部署Spring-boot+vue前后端分离项目
- Notifier 一文搞懂Linux内核通知链
- SpringBoot 各种 Web 容器服开启 AccessLog 日志
- 初识SpringBoot Starter
- 月亮|年度最大“超级月亮”来了!摄影师晒小米12S Ultra实拍:环形山清晰可见
- 艺术品|和田玉最主要的分清点,搞懂什么是商品,什么是可观赏的艺术品
