Spring攔截器中注入Bean失敗解放方案詳解
簡介
說明
本文用示例介紹如何解決攔截器中注入Bean失敗的問題。
場景
Token攔截器中需要用@Autowired注入JavaJwtUtil類,結(jié)果發(fā)現(xiàn)注入的JavaJwtUtil為Null。
原因
攔截器的配置類是以new JwtInterceptor的方式使用的,那么這個(gè)JwtInterceptor不受Spring管理。因此,里邊@Autowired注入JavaJwtUtil是不會(huì)注入進(jìn)去的。
問題重現(xiàn)
代碼
application.yml
server:
port: 8080
spring:
application:
name: springboot-jwt
config:
jwt:
# 密鑰
secret: abcd1234
# token過期時(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 {
// 如果不是映射到方法直接通過
if (!(handler instanceof HandlerMethod)) {
return true;
}
//放過不需要驗(yàn)證的頁面。
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 {
//過期時(shí)間
@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;
}
}
//校驗(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 無效,請重新獲取");
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ù)庫中是否一致,如不一致,直接返回失敗
// 通過userName,password從數(shù)據(jù)庫中獲取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)證通過";
}
}測試
訪問: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();
}
}攔截器(此時(shí)無需@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;
}
//放過不需要驗(yàn)證的頁面。
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)文章
Java中l(wèi)ambda表達(dá)式的基本運(yùn)用
大家好,本篇文章主要講的是Java中l(wèi)ambda表達(dá)式的基本運(yùn)用,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下2022-01-01
spring boot搭建文件服務(wù)器解決同時(shí)上傳多個(gè)圖片和下載的問題
這篇文章主要介紹了spring boot搭建文件服務(wù)器解決同時(shí)上傳多個(gè)圖片和下載的問題,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-11-11
Mybatis實(shí)現(xiàn)單個(gè)和批量定義別名typeAliases
這篇文章主要介紹了Mybatis實(shí)現(xiàn)單個(gè)和批量定義別名typeAliases,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
Spring Boot集成MyBatis實(shí)現(xiàn)通用Mapper的配置及使用
關(guān)于MyBatis,大部分人都很熟悉。MyBatis 是一款優(yōu)秀的持久層框架,它支持定制化 SQL、存儲(chǔ)過程以及高級映射。這篇文章主要介紹了Spring Boot集成MyBatis實(shí)現(xiàn)通用Mapper,需要的朋友可以參考下2018-08-08
Mybatis關(guān)聯(lián)查詢遇到的坑-無主鍵的關(guān)聯(lián)數(shù)據(jù)去重問題
這篇文章主要介紹了Mybatis關(guān)聯(lián)查詢遇到的坑-無主鍵的關(guān)聯(lián)數(shù)據(jù)去重問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03
SpringBoot中使用MyBatis-Plus實(shí)現(xiàn)分頁接口的詳細(xì)教程
MyBatis-Plus是一個(gè)MyBatis的增強(qiáng)工具,在MyBatis的基礎(chǔ)上只做增強(qiáng)不做改變,為簡化開發(fā)、提高效率而生,在SpringBoot項(xiàng)目中使用MyBatis-Plus可以大大簡化分頁邏輯的編寫,本文將介紹如何在 SpringBoot項(xiàng)目中使用MyBatis-Plus實(shí)現(xiàn)分頁接口2024-03-03
java中對字符串每個(gè)字符統(tǒng)計(jì)的方法
java中對字符串每個(gè)字符統(tǒng)計(jì)的方法,需要的朋友可以參考一下2013-03-03

