火影 发表于 2022-6-26 14:51:46

Spring(SpringBoot)--解决拦截器中注入Bean失败的问题

原文网址:Spring(SpringBoot)--解决拦截器中注入Bean失败的问题_IT利刃出鞘的博客-CSDN博客
简介

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

代码

application.yml
server:
port: 8080
spring:
application:
    name: springboot-jwt
config:
jwt:
    # 密钥
    secret: abcd1234
    # token过期时间(5分钟)。单位:毫秒.
    expire: 300000 拦截器配置
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
      registry.addInterceptor(new JwtInterceptor());
    }
} 拦截器
package com.example.demo.interceptor;

import com.example.demo.util.JavaJwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;

@Slf4j
@Component
public class JwtInterceptor implements HandlerInterceptor {
    @Autowired
    JavaJwtUtil javaJwtUtil;

    List<String> whiteList = Arrays.asList(
            "/auth/login",
            "/error"
    );

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler) throws Exception {
      // 如果不是映射到方法直接通过
      if (!(handler instanceof HandlerMethod)) {
            return true;
      }


      //放过不需要验证的页面。
      String uri = request.getRequestURI();
      if (whiteList.contains(uri)) {
            return true;
      }

      // 头部和参数都查看一下是否有token
      String token = request.getHeader("token");
      if (StringUtils.isEmpty(token)) {
            token = request.getParameter("token");
            if (StringUtils.isEmpty(token)) {
                throw new RuntimeException("token是空的");
            }
      }

      if (!javaJwtUtil.verifyToken(token)) {
            log.error("token无效");
            return false;
      }

      String userId = javaJwtUtil.getUserIdByToken(token);
      log.info("userId:" + userId);
      String userName = javaJwtUtil.getUserNameByToken(token);
      log.info("userName:" + userName);
      return true;
    }
} Jwt工具类
package com.example.demo.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class JavaJwtUtil {
    //过期时间
    @Value("${config.jwt.expire}")
    private Long EXPIRE_TIME;

    //密钥
    @Value("${config.jwt.secret}")
    private String SECRET;

    // 生成Token,五分钟后过期
    public String createToken(String userId) {
      try {
            Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            return JWT.create()
                  // 将 user id 保存到 token 里面
                  .withAudience(userId)
                  // date之后,token过期
                  .withExpiresAt(date)
                  // token 的密钥
                  .sign(algorithm);
      } catch (Exception e) {
            return null;
      }
    }

    // 根据token获取userId
    public String getUserIdByToken(String token) {
      try {
            String userId = JWT.decode(token).getAudience().get(0);
            return userId;
      } catch (JWTDecodeException e) {
            return null;
      }
    }

    // 根据token获取userName
    public String getUserNameByToken(String token) {
      try {
            String userName = JWT.decode(token).getSubject();
            return userName;
      } catch (JWTDecodeException e) {
            return null;
      }
    }

    //校验token
    public boolean verifyToken(String token) {
      try {
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            JWTVerifier verifier = JWT.require(algorithm)
                  // .withIssuer("auth0")
                  // .withClaim("username", username)
                  .build();
            DecodedJWT jwt = verifier.verify(token);
            return true;
      } catch (JWTVerificationException exception) {
//            throw new RuntimeException("token 无效,请重新获取");
            return false;
      }
    }
}  Controller
package com.example.demo.controller;

import com.example.demo.util.JavaJwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/auth")
public class AuthController {
    @Autowired
    JavaJwtUtil javaJwtUtil;

    @RequestMapping("/login")
    public String login() {
      // 验证userName,password和数据库中是否一致,如不一致,直接返回失败
      // 通过userName,password从数据库中获取userId

      String userId = 5 + "";
      String token = javaJwtUtil.createToken(userId);
      System.out.println("token:" + token);
      return token;
    }

    //需要token验证
    @RequestMapping("/info")
    public String info() {
      return"验证通过";
    }
} 测试

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

方案简述
配置类中将new JwtInterceptor()改为Bean的方式
配置类
package com.example.demo.interceptor;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
      registry.addInterceptor(getJwtInterceptor());
    }

    @Bean
    JwtInterceptor getJwtInterceptor() {
      return new JwtInterceptor();
    }
} 拦截器(此时无需@Component)
package com.example.demo.interceptor;

import com.example.demo.util.JavaJwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;

@Slf4j
public class JwtInterceptor implements HandlerInterceptor {
    @Autowired
    JavaJwtUtil javaJwtUtil;

    List<String> whiteList = Arrays.asList(
            "/auth/login",
            "/error"
    );

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler) throws Exception {
      // 如果不是映射到方法直接通过
      if (!(handler instanceof HandlerMethod)) {
            return true;
      }


      //放过不需要验证的页面。
      String uri = request.getRequestURI();
      if (whiteList.contains(uri)) {
            return true;
      }

      // 头部和参数都查看一下是否有token
      String token = request.getHeader("token");
      if (StringUtils.isEmpty(token)) {
            token = request.getParameter("token");
            if (StringUtils.isEmpty(token)) {
                throw new RuntimeException("token是空的");
            }
      }

      if (!javaJwtUtil.verifyToken(token)) {
            log.error("token无效");
            return false;
      }

      String userId = javaJwtUtil.getUserIdByToken(token);
      log.info("userId:" + userId);
      String userName = javaJwtUtil.getUserNameByToken(token);
      log.info("userName:" + userName);
      return true;
    }
}

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: Spring(SpringBoot)--解决拦截器中注入Bean失败的问题