Spring攔截器中注入Bean失敗解放方案詳解
簡介
說明
本文用示例介紹如何解決攔截器中注入Bean失敗的問題。
場景
Token攔截器中需要用@Autowired注入JavaJwtUtil類,結(jié)果發(fā)現(xiàn)注入的JavaJwtUtil為Null。
原因
攔截器的配置類是以new JwtInterceptor的方式使用的,那么這個JwtInterceptor不受Spring管理。因此,里邊@Autowired注入JavaJwtUtil是不會注入進去的。
問題重現(xiàn)
代碼
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; } // 頭部和參數(shù)都查看一下是否有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; } } // 根據(jù)token獲取userId public String getUserIdByToken(String token) { try { String userId = JWT.decode(token).getAudience().get(0); return userId; } catch (JWTDecodeException e) { return null; } } // 根據(jù)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和數(shù)據(jù)庫中是否一致,如不一致,直接返回失敗 // 通過userName,password從數(shù)據(jù)庫中獲取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
前端結(jié)果:一串token字符串
訪問:http://localhost:8080/auth/info(以token作為header或者參數(shù))
后端結(jié)果
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; } // 頭部和參數(shù)都查看一下是否有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; } }
到此這篇關(guān)于Spring攔截器中注入Bean失敗解放方案詳解的文章就介紹到這了,更多相關(guān)Spring Bean內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot feign動態(tài)設置數(shù)據(jù)源(https請求)
這篇文章主要介紹了SpringBoot如何在運行時feign動態(tài)添加數(shù)據(jù)源,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2021-08-08Spring?IOC中對象的創(chuàng)建、策略及銷毀時機和生命周期詳解
這篇文章主要介紹了Spring?IOC中對象的創(chuàng)建、策略及銷毀時機和生命周期詳解,Spring默認使用類的空參構(gòu)造方法創(chuàng)建bean,假如類沒有空參構(gòu)造方法,將無法完成bean的創(chuàng)建,需要的朋友可以參考下2023-08-08IntelliJ IDEA配置Tomcat(完整版圖文教程)
這篇文章主要介紹了IntelliJ IDEA配置Tomcat(完整版圖文教程),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-05-05MyBatis基于pagehelper實現(xiàn)分頁原理及代碼實例
這篇文章主要介紹了MyBatis基于pagehelper實現(xiàn)分頁原理及代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-06-06