Skip to content

拦截器配置类添加的自定义拦截类是空值

项目: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();
    }
}

如有转载或 CV 的请标注本站原文地址