/**
 * 自定义拦截器类
 */
public class V8Interceptor implements HandlerInterceptor {
    @Autowired
    private Environment env; //自动注入环境变量获取配置
    @Autowired
    private StringRedisTemplate redisTmp;

    // token规则为 user-reids-token:userId : UUID
    private static String USER_REDIS_TOKEN = "api-token";


    /**
     * 判断用户是否登录
     *  若用户 username 不存在,则为未登录
     *  若用户 username 存在,则判断 usertoken 是否存在
     *      若存在,则用户状态为已登录
     *      若不存在,则用户状态为登录超时
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     *
     */


    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 如果是 嗅探请求,则直接放行
        String methodname = request.getMethod();

        if("OPTIONS".equals(methodname)){
            return true;
        }
 
        //例如:/api/wx/getmsg
        String requrl = request.getRequestURI();
 
        if (
                (requrl.indexOf("/api/wx/")>=0) 
        ){
            //针对移动端接口的拦截处理
            String local_wxapitoken = env.getProperty("wxapitoken");
            String req_wxapitoken = request.getHeader("wxapitoken");
            if (!local_wxapitoken.equals(req_wxapitoken)){
                //再判断是否提供了username和usertoken
                String username = request.getHeader("username");
                String userOldToken = request.getHeader("usertoken");
                String v8_acname = env.getProperty("acname");
                String errormsg = checkUserTokenInfo(username,userOldToken,acname);

                if (errormsg.equals("")){
                    return true;
                }else{
                    String info = "无效的wxapitoken或usertoken";
                    returnErrorResponse(response, JsonUtils.getErrorJson("1000", info));
                    return false;
                }
            }else{
                return true;
            }
        } else{ //其他情况处理
                String username = request.getHeader("username");
                String userOldToken = request.getHeader("usertoken");
                String v8_acname = env.getProperty("acname");
                String errormsg = checkUserTokenInfo(username,userOldToken,acname);

                if (errormsg.equals("")){
                    return true;
                }else{
                    returnErrorResponse(response, JsonUtils.getErrorJson("1000", errormsg));
                    return false;
                } 
    }

    //判断username和usertoken是否合法
    //返回:空字符表示正确,其他表示错误原因
    public String checkUserTokenInfo(String username,String userOldToken,String acname){
        String errormsg = "";

        if (StrUtils.isNotBlank(username) && StrUtils.isNotBlank(userOldToken)) {
            //token的key名称格式 api-token:acname:username
            String userTokenKey = USER_REDIS_TOKEN + ":" + acname + ":" + username;
            String userToken = "";
            if (redisTmp.hasKey(userTokenKey)) {
                userToken = redisTmp.opsForValue().get(userTokenKey).toString();
            }

            // 用户有token,但最新token为空,说明登录状态过期
            if (StrUtils.isBlank(userToken)) {
                errormsg = "登录过期或未登录,请重新登录";
                return errormsg;
            }

            // 两个token不一致,可能是恶意用户乱填token
            if (!userOldToken.equals(userToken)) {
                errormsg = "无效token,请重新登录";
                return errormsg;
            }
        } else {
            System.out.println("该用户没有登录");
            errormsg = "请登录后再操作";
            return errormsg;
        }

        return errormsg;
    }


    public void returnErrorResponse(HttpServletResponse response, String jsonstr) throws IOException {
        OutputStream outputStream = null ;
        try {
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            outputStream = response.getOutputStream();
            outputStream.write(jsonstr.getBytes("UTF-8"));
            outputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(outputStream != null){
                outputStream.close();
            }
        }
    }


}

 

@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    @Bean
    public V8Interceptor vxInterceptor(){
        return new V8Interceptor();
    }


    @Override 
    public void addCorsMappings(CorsRegistry registry) {
        //添加映射路径
        registry.addMapping("/**") 
                .allowedOrigins("*")
                //是否发送Cookie信息, allowedOrigins设置*,则allowCredentials不能设置true
                .allowCredentials(false)
                //放行哪些原始域(请求方式)
                .allowedMethods("GET","POST", "PUT", "DELETE")
                //放行哪些原始域(头部信息)
                .allowedHeaders("*")
                //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
                .exposedHeaders("username", "usertoken","wxapitoken","lan_ip","net_ip");
    }


    /**
     * 设置拦截的url路径
     *
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry){
        //设置要拦截的接口或目录
        List listOfVerify = Arrays.asList( "/api/file/**",
                "/api/wx/**" 
            );

        //设置要拦截的接口
        List listOfExc = Arrays.asList(
                "/api/login/changeUserPwd" 
            );

        registry.addInterceptor(vxInterceptor())
                .addPathPatterns(listOfVerify)
                .excludePathPatterns(listOfExc);
        super.addInterceptors(registry);
    } 
}