Spring拦截器中注入Bean失败解放方案详解

 更新时间:2022年06月21日 08:34:39   作者:IT利刃出鞘  
这两天遇到SpringBoot拦截器中Bean无法注入问题。下面介绍关于SpringBoot拦截器中Bean无法注入的问题解决方案,感兴趣的朋友一起看看吧

简介

说明

本文用示例介绍如何解决拦截器中注入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) ~[main/:na]

解决方案

方案简述

配置类中将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;
    }
}

到此这篇关于Spring拦截器中注入Bean失败解放方案详解的文章就介绍到这了,更多相关Spring Bean内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 浅谈一下Java中的内存模型JMM

    浅谈一下Java中的内存模型JMM

    这篇文章主要介绍了浅谈一下Java中的内存模型JMM,JMM,全程是 Java Memory Model ,直译就是 Java 内存模型,根据这个名字,可以知道它是 Java 设计用来管理内存的一个模型,需要的朋友可以参考下
    2023-08-08
  • Java中Thread类的使用和它的属性

    Java中Thread类的使用和它的属性

    在java中可以进行多线程编程,在java标准库中提供了一个Thread类,来表示线程操作,本文主要介绍了Java中Thread类的使用和它的属性,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • SpringBoot feign动态设置数据源(https请求)

    SpringBoot feign动态设置数据源(https请求)

    这篇文章主要介绍了SpringBoot如何在运行时feign动态添加数据源,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2021-08-08
  • Spring IOC中对象的创建、策略及销毁时机和生命周期详解

    Spring IOC中对象的创建、策略及销毁时机和生命周期详解

    这篇文章主要介绍了Spring IOC中对象的创建、策略及销毁时机和生命周期详解,Spring默认使用类的空参构造方法创建bean,假如类没有空参构造方法,将无法完成bean的创建,需要的朋友可以参考下
    2023-08-08
  • Android中几种图片特效的处理的实现方法

    Android中几种图片特效的处理的实现方法

    这篇文章主要介绍了 Android中几种图片特效的处理的实现方法的相关资料,这里有放大缩小图片,获得圆角图片,获得带倒影图片的几种方法,需要的朋友可以参考下
    2017-08-08
  • IntelliJ IDEA配置Tomcat(完整版图文教程)

    IntelliJ IDEA配置Tomcat(完整版图文教程)

    这篇文章主要介绍了IntelliJ IDEA配置Tomcat(完整版图文教程),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-05-05
  • Java设计模式之组合模式的示例详解

    Java设计模式之组合模式的示例详解

    组合模式,又叫部分整体模式,它创建了对象组的数据结构组合模式使得用户对单个对象和组合对象的访问具有一致性。本文将通过示例为大家详细介绍一下组合模式,需要的可以参考一下
    2022-03-03
  • SpringMVC超详细讲解视图和视图解析器

    SpringMVC超详细讲解视图和视图解析器

    这篇文章主要介绍了springMVC中的视图与视图解析器,springMVC视图的种类很多,默认有转发视图和重定向视图,本文就每一种视图给大家详细介绍,需要的朋友可以参考下
    2022-06-06
  • MyBatis基于pagehelper实现分页原理及代码实例

    MyBatis基于pagehelper实现分页原理及代码实例

    这篇文章主要介绍了MyBatis基于pagehelper实现分页原理及代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-06-06
  • mybatis通过if语句实现增删改查操作

    mybatis通过if语句实现增删改查操作

    这篇文章主要介绍了mybatis通过if语句实现增删改查操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-11-11

最新评论