ToB企服应用市场:ToB评测及商务社交产业平台

标题: Spring(SpringBoot)--解决拦截器中注入Bean失败的问题 [打印本页]

作者: 火影    时间: 2022-6-26 14:51
标题: Spring(SpringBoot)--解决拦截器中注入Bean失败的问题
原文网址:Spring(SpringBoot)--解决拦截器中注入Bean失败的问题_IT利刃出鞘的博客-CSDN博客
简介

说明
        本文用示例介绍如何解决拦截器中注入Bean失败的问题。
场景
        Token拦截器中需要用@Autowired注入JavaJwtUtil类,结果发现注入的JavaJwtUtil为Null。
原因
        拦截器的配置类是以new JwtInterceptor的方式使用的,那么这个JwtInterceptor不受Spring管理。因此,里边@Autowired注入JavaJwtUtil是不会注入进去的。
问题重现

代码

application.yml
  1. server:
  2.   port: 8080
  3. spring:
  4.   application:
  5.     name: springboot-jwt
  6. config:
  7.   jwt:
  8.     # 密钥
  9.     secret: abcd1234
  10.     # token过期时间(5分钟)。单位:毫秒.
  11.     expire: 300000
复制代码
拦截器配置
  1. @Configuration
  2. public class InterceptorConfig implements WebMvcConfigurer {
  3.     @Override
  4.     public void addInterceptors(InterceptorRegistry registry) {
  5.         registry.addInterceptor(new JwtInterceptor());
  6.     }
  7. }
复制代码
拦截器
  1. package com.example.demo.interceptor;
  2. import com.example.demo.util.JavaJwtUtil;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.springframework.beans.BeansException;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.context.ApplicationContext;
  7. import org.springframework.context.ApplicationContextAware;
  8. import org.springframework.stereotype.Component;
  9. import org.springframework.util.StringUtils;
  10. import org.springframework.web.method.HandlerMethod;
  11. import org.springframework.web.servlet.HandlerInterceptor;
  12. import javax.annotation.PostConstruct;
  13. import javax.servlet.http.HttpServletRequest;
  14. import javax.servlet.http.HttpServletResponse;
  15. import java.util.Arrays;
  16. import java.util.List;
  17. @Slf4j
  18. @Component
  19. public class JwtInterceptor implements HandlerInterceptor {
  20.     @Autowired
  21.     JavaJwtUtil javaJwtUtil;
  22.     List<String> whiteList = Arrays.asList(
  23.             "/auth/login",
  24.             "/error"
  25.     );
  26.     @Override
  27.     public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
  28.                              Object handler) throws Exception {
  29.         // 如果不是映射到方法直接通过
  30.         if (!(handler instanceof HandlerMethod)) {
  31.             return true;
  32.         }
  33.         //放过不需要验证的页面。
  34.         String uri = request.getRequestURI();
  35.         if (whiteList.contains(uri)) {
  36.             return true;
  37.         }
  38.         // 头部和参数都查看一下是否有token
  39.         String token = request.getHeader("token");
  40.         if (StringUtils.isEmpty(token)) {
  41.             token = request.getParameter("token");
  42.             if (StringUtils.isEmpty(token)) {
  43.                 throw new RuntimeException("token是空的");
  44.             }
  45.         }
  46.         if (!javaJwtUtil.verifyToken(token)) {
  47.             log.error("token无效");
  48.             return false;
  49.         }
  50.         String userId = javaJwtUtil.getUserIdByToken(token);
  51.         log.info("userId:" + userId);
  52.         String userName = javaJwtUtil.getUserNameByToken(token);
  53.         log.info("userName:" + userName);
  54.         return true;
  55.     }
  56. }
复制代码
Jwt工具类
  1. package com.example.demo.util;
  2. import com.auth0.jwt.JWT;
  3. import com.auth0.jwt.JWTVerifier;
  4. import com.auth0.jwt.algorithms.Algorithm;
  5. import com.auth0.jwt.exceptions.JWTDecodeException;
  6. import com.auth0.jwt.exceptions.JWTVerificationException;
  7. import com.auth0.jwt.interfaces.DecodedJWT;
  8. import org.springframework.beans.factory.annotation.Value;
  9. import org.springframework.stereotype.Component;
  10. import java.util.Date;
  11. @Component
  12. public class JavaJwtUtil {
  13.     //过期时间
  14.     @Value("${config.jwt.expire}")
  15.     private Long EXPIRE_TIME;
  16.     //密钥
  17.     @Value("${config.jwt.secret}")
  18.     private String SECRET;
  19.     // 生成Token,五分钟后过期
  20.     public String createToken(String userId) {
  21.         try {
  22.             Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
  23.             Algorithm algorithm = Algorithm.HMAC256(SECRET);
  24.             return JWT.create()
  25.                     // 将 user id 保存到 token 里面
  26.                     .withAudience(userId)
  27.                     // date之后,token过期
  28.                     .withExpiresAt(date)
  29.                     // token 的密钥
  30.                     .sign(algorithm);
  31.         } catch (Exception e) {
  32.             return null;
  33.         }
  34.     }
  35.     // 根据token获取userId
  36.     public String getUserIdByToken(String token) {
  37.         try {
  38.             String userId = JWT.decode(token).getAudience().get(0);
  39.             return userId;
  40.         } catch (JWTDecodeException e) {
  41.             return null;
  42.         }
  43.     }
  44.     // 根据token获取userName
  45.     public String getUserNameByToken(String token) {
  46.         try {
  47.             String userName = JWT.decode(token).getSubject();
  48.             return userName;
  49.         } catch (JWTDecodeException e) {
  50.             return null;
  51.         }
  52.     }
  53.     //校验token
  54.     public boolean verifyToken(String token) {
  55.         try {
  56.             Algorithm algorithm = Algorithm.HMAC256(SECRET);
  57.             JWTVerifier verifier = JWT.require(algorithm)
  58.                     // .withIssuer("auth0")
  59.                     // .withClaim("username", username)
  60.                     .build();
  61.             DecodedJWT jwt = verifier.verify(token);
  62.             return true;
  63.         } catch (JWTVerificationException exception) {
  64. //            throw new RuntimeException("token 无效,请重新获取");
  65.             return false;
  66.         }
  67.     }
  68. }
复制代码
 Controller
  1. package com.example.demo.controller;
  2. import com.example.demo.util.JavaJwtUtil;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.web.bind.annotation.RequestMapping;
  5. import org.springframework.web.bind.annotation.RestController;
  6. @RestController
  7. @RequestMapping("/auth")
  8. public class AuthController {
  9.     @Autowired
  10.     JavaJwtUtil javaJwtUtil;
  11.     @RequestMapping("/login")
  12.     public String login() {
  13.         // 验证userName,password和数据库中是否一致,如不一致,直接返回失败
  14.         // 通过userName,password从数据库中获取userId
  15.         String userId = 5 + "";
  16.         String token = javaJwtUtil.createToken(userId);
  17.         System.out.println("token:" + token);
  18.         return token;
  19.     }
  20.     //需要token验证
  21.     @RequestMapping("/info")
  22.     public String info() {
  23.         return  "验证通过";
  24.     }
  25. }
复制代码
测试

访问:http://localhost:8080/auth/login 
前端结果:一串token字符串
访问:http://localhost:8080/auth/info(以token作为header或者参数)
后端结果
  1. java.lang.NullPointerException: null
  2.         at com.example.demo.interceptor.JwtInterceptor.preHandle(JwtInterceptor.java:55) ~[main/:na]
复制代码
解决方案

方案简述
配置类中将new JwtInterceptor()改为Bean的方式
配置类
  1. package com.example.demo.interceptor;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
  5. import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  6. @Configuration
  7. public class InterceptorConfig implements WebMvcConfigurer {
  8.     @Override
  9.     public void addInterceptors(InterceptorRegistry registry) {
  10.         registry.addInterceptor(getJwtInterceptor());
  11.     }
  12.     @Bean
  13.     JwtInterceptor getJwtInterceptor() {
  14.         return new JwtInterceptor();
  15.     }
  16. }
复制代码
拦截器(此时无需@Component)
  1. package com.example.demo.interceptor;
  2. import com.example.demo.util.JavaJwtUtil;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.util.StringUtils;
  6. import org.springframework.web.method.HandlerMethod;
  7. import org.springframework.web.servlet.HandlerInterceptor;
  8. import javax.servlet.http.HttpServletRequest;
  9. import javax.servlet.http.HttpServletResponse;
  10. import java.util.Arrays;
  11. import java.util.List;
  12. @Slf4j
  13. public class JwtInterceptor implements HandlerInterceptor {
  14.     @Autowired
  15.     JavaJwtUtil javaJwtUtil;
  16.     List<String> whiteList = Arrays.asList(
  17.             "/auth/login",
  18.             "/error"
  19.     );
  20.     @Override
  21.     public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
  22.                              Object handler) throws Exception {
  23.         // 如果不是映射到方法直接通过
  24.         if (!(handler instanceof HandlerMethod)) {
  25.             return true;
  26.         }
  27.         //放过不需要验证的页面。
  28.         String uri = request.getRequestURI();
  29.         if (whiteList.contains(uri)) {
  30.             return true;
  31.         }
  32.         // 头部和参数都查看一下是否有token
  33.         String token = request.getHeader("token");
  34.         if (StringUtils.isEmpty(token)) {
  35.             token = request.getParameter("token");
  36.             if (StringUtils.isEmpty(token)) {
  37.                 throw new RuntimeException("token是空的");
  38.             }
  39.         }
  40.         if (!javaJwtUtil.verifyToken(token)) {
  41.             log.error("token无效");
  42.             return false;
  43.         }
  44.         String userId = javaJwtUtil.getUserIdByToken(token);
  45.         log.info("userId:" + userId);
  46.         String userName = javaJwtUtil.getUserNameByToken(token);
  47.         log.info("userName:" + userName);
  48.         return true;
  49.     }
  50. }
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4