Spring攔截器中注入Bean失敗解放方案詳解
簡(jiǎn)介
說(shuō)明
本文用示例介紹如何解決攔截器中注入Bean失敗的問(wèn)題。
場(chǎng)景
Token攔截器中需要用@Autowired注入JavaJwtUtil類,結(jié)果發(fā)現(xiàn)注入的JavaJwtUtil為Null。
原因
攔截器的配置類是以new JwtInterceptor的方式使用的,那么這個(gè)JwtInterceptor不受Spring管理。因此,里邊@Autowired注入JavaJwtUtil是不會(huì)注入進(jìn)去的。
問(wèn)題重現(xiàn)
代碼
application.yml
server:
port: 8080
spring:
application:
name: springboot-jwt
config:
jwt:
# 密鑰
secret: abcd1234
# token過(guò)期時(shí)間(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 { // 如果不是映射到方法直接通過(guò) if (!(handler instanceof HandlerMethod)) { return true; } //放過(guò)不需要驗(yàn)證的頁(yè)面。 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無(wú)效"); 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 { //過(guò)期時(shí)間 @Value("${config.jwt.expire}") private Long EXPIRE_TIME; //密鑰 @Value("${config.jwt.secret}") private String SECRET; // 生成Token,五分鐘后過(guò)期 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過(guò)期 .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; } } //校驗(yàn)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 無(wú)效,請(qǐng)重新獲取"); 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() { // 驗(yàn)證userName,password和數(shù)據(jù)庫(kù)中是否一致,如不一致,直接返回失敗 // 通過(guò)userName,password從數(shù)據(jù)庫(kù)中獲取userId String userId = 5 + ""; String token = javaJwtUtil.createToken(userId); System.out.println("token:" + token); return token; } //需要token驗(yàn)證 @RequestMapping("/info") public String info() { return "驗(yàn)證通過(guò)"; } }
測(cè)試
訪問(wèn):http://localhost:8080/auth/login
前端結(jié)果:一串token字符串
訪問(wèn):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]
解決方案
方案簡(jiǎn)述
配置類中將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(); } }
攔截器(此時(shí)無(wú)需@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 { // 如果不是映射到方法直接通過(guò) if (!(handler instanceof HandlerMethod)) { return true; } //放過(guò)不需要驗(yàn)證的頁(yè)面。 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無(wú)效"); 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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot feign動(dòng)態(tài)設(shè)置數(shù)據(jù)源(https請(qǐng)求)
這篇文章主要介紹了SpringBoot如何在運(yùn)行時(shí)feign動(dòng)態(tài)添加數(shù)據(jù)源,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2021-08-08Spring?IOC中對(duì)象的創(chuàng)建、策略及銷毀時(shí)機(jī)和生命周期詳解
這篇文章主要介紹了Spring?IOC中對(duì)象的創(chuàng)建、策略及銷毀時(shí)機(jī)和生命周期詳解,Spring默認(rèn)使用類的空參構(gòu)造方法創(chuàng)建bean,假如類沒(méi)有空參構(gòu)造方法,將無(wú)法完成bean的創(chuàng)建,需要的朋友可以參考下2023-08-08Android中幾種圖片特效的處理的實(shí)現(xiàn)方法
這篇文章主要介紹了 Android中幾種圖片特效的處理的實(shí)現(xiàn)方法的相關(guān)資料,這里有放大縮小圖片,獲得圓角圖片,獲得帶倒影圖片的幾種方法,需要的朋友可以參考下2017-08-08IntelliJ IDEA配置Tomcat(完整版圖文教程)
這篇文章主要介紹了IntelliJ IDEA配置Tomcat(完整版圖文教程),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-05-05MyBatis基于pagehelper實(shí)現(xiàn)分頁(yè)原理及代碼實(shí)例
這篇文章主要介紹了MyBatis基于pagehelper實(shí)現(xiàn)分頁(yè)原理及代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06mybatis通過(guò)if語(yǔ)句實(shí)現(xiàn)增刪改查操作
這篇文章主要介紹了mybatis通過(guò)if語(yǔ)句實(shí)現(xiàn)增刪改查操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11