2、将AuthenticationManager接入到Spring容器中 。在上面service实现的时候有说到,Spring Security并没有将 AuthenticationManager 加入到容器中,因此我们需要手动将其加到Spring容器中再进行注入,这里同样借助SecurityConfig配置类重写 authenticationManagerBean方法 生成Bean 。
代码在下面配置放行时一起,毕竟都是在同一个配置类中3、放行登录接口 。大家可能会发现,当我们随便进入一个接口的时候,如 /hello ,请求都会被拦截下来,这是因为Spring Security底层就是一条过滤器链,默认是对所有接口进行拦截,因此我们就需要让框架对我们自定义的接口放行,让用户在不登录的情况下也能够访问登录接口 。
@Configurationpublic class SecurityConfig extends WebSecurityConfigurerAdapter {/** 这里使用了数组当作下方可变参数列表的参数 */private String[]matchers = new String[]{"/user/login"};/*** 将BCryptPasswordEncoder加入到容器中**/@Beanpublic PasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}/*** 将认证入口AuthenticationManager注入容器中用于用户认证**/@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}/*** 配置SpringSecurity对需要放行的接口放行**/@Overrideprotected void configure(HttpSecurity http) throws Exception {http//关闭csrf.csrf().disable()//不通过Session获取SecurityContext.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()// 对于登录接口 允许匿名访问,下面注释的是视频中的使用方式//.antMatchers("/user/login").anonymous().antMatchers(matchers).anonymous()// 除上面外的所有请求全部需要鉴权认证.anyRequest().authenticated();}}3.3.3、Bug跑起来 。这个时候我们就可以真正意义上使用自己的接口,调用自己的数据库进行登录操作啦,这里使用Postman进行测试(如果有自己的页面可以加入前端界面进行协调) 。
大家伙记得记得你们的redis要先跑起来!!!

文章插图
3.4、认证过滤器3.4.1、思路分析为什么这里我们还需要一个认证过滤器在这里呢?
是因为前面我们实现的只是简单的登录操作,但是总会有一些大聪明企图在未登录的情况下访问我们不给他访问的东西,因此我们就需要编写一个登录状态的一个认证拦截器对为登录的用户进行拦截,这就类似于初学过滤器写的登录拦截器中判断session是否存在一样 。
该过滤器会去获取 请求头中的token ,对token进行解析取出其中的 userId 。使用userId去redis中获取对应的LoginUser对象 。然后封装 Authentication 对象存入 SecurityContextHolder 。但是我们还需要思考一个问题,那就是Spring Security是存在自己的一套过滤器链的(可以回头看目录中的 2.1、过滤器链 ),那么我们这个过滤器应该放在过滤器链中的哪个位置呢?
答案是应该放在
UsernamePasswordAuthenticationFilter 的前面 。这是因为我们的登录接口是在这里被调用的,当过滤器链走到这里的时候就证明是开始获取账号密码的时候了,很显然我们目前只需要验证用户是否登录,获取账户密码的意义不大,因此需要放到他的前面去 。
3.4.2、具体实现主要流程有如下几步:
- 定义过滤器并将其 加入Spring容器 中,因为后面需要将其插入到过滤器链中;
- 获取 请求头中的token数据;
- 判断请求头中 是否携带token数据 ,若没有携带有两种可能:用户需要登录,正在访问登录接口准备账号密码登录;用户未登录或登录过期,导致无token或token已过期;
- 解析token 数据,从中拿到userId;
- 从 Redis 中获取用户数据,若Redis中无数据则证明登录已过期,抛异常提示;
- 将用户数据存入 SecurityContextHolder :因为这里是认证,是假设已经登录之后的状态,所以参数列表分别为用户数据,空,鉴权信息;如果是前面的还未登录状态,参数列表则为账号和密码两个参数;
- 将过滤器插入至过滤器链中 。
@Component@Slf4jpublic class JwtAuthenticationTokenFilter extends OncePerRequestFilter {@Autowiredprivate RedisCache redisCache;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {//获取tokenString token = request.getHeader("token");if (!StringUtils.hasText(token)) {log.info("无token");//放行filterChain.doFilter(request, response);return;}//解析tokenString userId;try {Claims claims = JwtUtil.parseJWT(token);userId = claims.getSubject();} catch (Exception e) {e.printStackTrace();throw new RuntimeException("token非法");}//从redis中获取用户信息String redisKey = "login:" + userId;LoginUser loginUser = redisCache.getCacheObject(redisKey);if(Objects.isNull(loginUser)){throw new RuntimeException("账号登录已超时,请重新登录");}//存入SecurityContextHolderUsernamePasswordAuthenticationToken authenticationToken =new UsernamePasswordAuthenticationToken(loginUser,null,null);SecurityContextHolder.getContext().setAuthentication(authenticationToken);//放行filterChain.doFilter(request, response);}}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- SpringBoot集成MyBatis的相关要点
- 一文搞懂响应式编程
- SpringBoot 整合 Elasticsearch 实现海量级数据搜索
- SpringBoot接口 - 如何生成接口文档之Swagger技术栈?
- windows基于nginx部署Spring-boot+vue前后端分离项目
- Notifier 一文搞懂Linux内核通知链
- SpringBoot 各种 Web 容器服开启 AccessLog 日志
- 初识SpringBoot Starter
- 月亮|年度最大“超级月亮”来了!摄影师晒小米12S Ultra实拍:环形山清晰可见
- 艺术品|和田玉最主要的分清点,搞懂什么是商品,什么是可观赏的艺术品
