• 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. }

  • 相关阅读:
    SpringBoot+Vue项目在线小说阅读平台
    Laravel一些优雅的写法
    C#大型互联网平台管理框架源码:基于ASP.NET MVC+EF6+Bootstrap开发,支持多数据库
    web前端——HTML(一看就会写自己的小网页)
    Maven部署打包多环境(开发、测试、生产)配置教程
    外贸线上推广引流的技巧
    [附源码]计算机毕业设计智能衣橱APPSpringboot程序
    pc与android设备进行通信
    MAC版idea如何安装maven?
    计算机毕业设计课题题目列表信息
  • 原文地址:https://blog.csdn.net/feiying0canglang/article/details/125322675