拦截器配置类添加的自定义拦截类是空值
项目:misszb/InterceptorConfiguration
遇到的问题
一、自定义了拦截类PermissionInterceptor和拦截配置类InterceptorConfiguration
二、将new PermissionInterceptor()添加到拦截器中
三、调用接口的时候报空指针错误
四、经过测试,发现是自定义的PermissionInterceptor类报错
InterceptorConfiguration.java
java
package com.zb.misszb.core.configuration;
import com.zb.misszb.core.interceptors.PermissionInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
// 拦截器配置类
@Configuration
public class InterceptorConfiguration implements WebMvcConfigurer {
// 将自定义的拦截类添加到拦截器中
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new PermissionInterceptor());
}
}
PermissionInterceptor.java
java
package com.zb.misszb.core.interceptors;
import com.auth0.jwt.interfaces.Claim;
import com.zb.misszb.core.LocalUser;
import com.zb.misszb.exception.http.ForbiddenException;
import com.zb.misszb.exception.http.NotFoundException;
import com.zb.misszb.exception.http.UnAuthenticatedException;
import com.zb.misszb.model.User;
import com.zb.misszb.service.UserService;
import com.zb.misszb.util.JwtToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.Optional;
@Component
public class PermissionInterceptor implements HandlerInterceptor {
@Autowired
private UserService userService;
// 请求在进入controller之前执行,其返回值表示是否中断后续操作,返回 true 表示继续向下执行,返回 false 表示中断后续操作。(返回true,false)
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Optional<ScopeLevel> scopeLevel = this.getScopeLevel(handler);
if (!scopeLevel.isPresent()) {
return true;
}
String bearerToken = request.getHeader("Authorization");
if (!StringUtils.hasLength(bearerToken)) {
throw new UnAuthenticatedException(10004);
}
if (!bearerToken.startsWith("Bearer")) {
throw new UnAuthenticatedException(10004);
}
String tokens[] = bearerToken.split(" ");
if (!(tokens.length == 2)) {
throw new UnAuthenticatedException(10004);
}
String token = tokens[1];
Optional<Map<String, Claim>> optionalMap = JwtToken.getClaims(token);
Map<String, Claim> map = optionalMap
.orElseThrow(() -> new UnAuthenticatedException(10004));
boolean valid = this.hasPermission(scopeLevel.get(), map);
if (valid) {
this.setToThreadLocal(map);
}
return valid;
}
private void setToThreadLocal(Map<String,Claim> map) {
Long uid = map.get("uid").asLong();
Integer scope = map.get("scope").asInt();
Optional<User> user = userService.getUserById(uid);
if (!user.isPresent()) {
throw new NotFoundException(20002);
}
LocalUser.set(user.get(), scope);
}
private boolean hasPermission(ScopeLevel scopeLevel, Map<String, Claim> map) {
Integer level = scopeLevel.value();
Integer scope = map.get("scope").asInt();
if (level > scope) {
throw new ForbiddenException(10005);
}
return true;
}
// 该方法在控制器处理请求方法调用之后、解析视图之前执行,可以通过此方法对请求域中的模型和视图做进一步修改。(无返回值)
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
// 该方法在视图渲染结束后执行,可以通过此方法实现资源清理、记录日志信息等工作。(无返回值)
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
LocalUser.clear();
}
// 获取ScopeLevel注解里的值
private Optional<ScopeLevel> getScopeLevel(Object handler) {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
ScopeLevel scopeLevel = handlerMethod.getMethod().getAnnotation(ScopeLevel.class);
if (scopeLevel == null) {
return Optional.empty();
}
return Optional.of(scopeLevel);
}
return Optional.empty();
}
}
分析
经过分析,发现出问题的原因是:拦截器配置类中new的PermissionInterceptor对象和用@Bean注解注入到容器里的对象不是同一个
解决
在拦截器配置类,需要将new的PermissionInterceptor对象注入到容器里,然后将注入到容器中的对象添加到拦截器中
InterceptorConfiguration.java
java
package com.zb.misszb.core.configuration;
import com.zb.misszb.core.interceptors.PermissionInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
// 拦截器配置类
@Configuration
public class InterceptorConfiguration implements WebMvcConfigurer {
@Bean
public HandlerInterceptor getPermissionInterceptor() {
return new PermissionInterceptor();
}
// 将自定义的拦截类添加到拦截器中
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(this.getPermissionInterceptor());
}
}
PermissionInterceptor.java
java
package com.zb.misszb.core.interceptors;
import com.auth0.jwt.interfaces.Claim;
import com.zb.misszb.core.LocalUser;
import com.zb.misszb.exception.http.ForbiddenException;
import com.zb.misszb.exception.http.NotFoundException;
import com.zb.misszb.exception.http.UnAuthenticatedException;
import com.zb.misszb.model.User;
import com.zb.misszb.service.UserService;
import com.zb.misszb.util.JwtToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.Optional;
public class PermissionInterceptor implements HandlerInterceptor {
@Autowired
private UserService userService;
// 请求在进入controller之前执行,其返回值表示是否中断后续操作,返回 true 表示继续向下执行,返回 false 表示中断后续操作。(返回true,false)
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Optional<ScopeLevel> scopeLevel = this.getScopeLevel(handler);
if (!scopeLevel.isPresent()) {
return true;
}
String bearerToken = request.getHeader("Authorization");
if (!StringUtils.hasLength(bearerToken)) {
throw new UnAuthenticatedException(10004);
}
if (!bearerToken.startsWith("Bearer")) {
throw new UnAuthenticatedException(10004);
}
String tokens[] = bearerToken.split(" ");
if (!(tokens.length == 2)) {
throw new UnAuthenticatedException(10004);
}
String token = tokens[1];
Optional<Map<String, Claim>> optionalMap = JwtToken.getClaims(token);
Map<String, Claim> map = optionalMap
.orElseThrow(() -> new UnAuthenticatedException(10004));
boolean valid = this.hasPermission(scopeLevel.get(), map);
if (valid) {
this.setToThreadLocal(map);
}
return valid;
}
private void setToThreadLocal(Map<String,Claim> map) {
Long uid = map.get("uid").asLong();
Integer scope = map.get("scope").asInt();
Optional<User> user = userService.getUserById(uid);
if (!user.isPresent()) {
throw new NotFoundException(20002);
}
LocalUser.set(user.get(), scope);
}
private boolean hasPermission(ScopeLevel scopeLevel, Map<String, Claim> map) {
Integer level = scopeLevel.value();
Integer scope = map.get("scope").asInt();
if (level > scope) {
throw new ForbiddenException(10005);
}
return true;
}
// 该方法在控制器处理请求方法调用之后、解析视图之前执行,可以通过此方法对请求域中的模型和视图做进一步修改。(无返回值)
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
// 该方法在视图渲染结束后执行,可以通过此方法实现资源清理、记录日志信息等工作。(无返回值)
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
LocalUser.clear();
}
// 获取ScopeLevel注解里的值
private Optional<ScopeLevel> getScopeLevel(Object handler) {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
ScopeLevel scopeLevel = handlerMethod.getMethod().getAnnotation(ScopeLevel.class);
if (scopeLevel == null) {
return Optional.empty();
}
return Optional.of(scopeLevel);
}
return Optional.empty();
}
}