拦截器Interceptor实现登录校验

登录校验

①、准备工具类AuthContextUtil创建ThreadLocal

public class AuthContextUtil{
	
	private static final ThreadLocal<SysUser> threadLocal = new ThreadLocal<>();

	public static void set(SysUser sysUser){
		threadLocal.set(sysUser);
	}

	public static SysUser get(){
		return threadLocal.get();
	}

	public static void remove(){
		threadLocal.remove();
	}
}

②、创建拦截器

@Component
public class LoginAuthInterceptor implements HandlerInterceptor{
	
	@Autowired
	private RedisTemplate<String,String> redisTemplate;

	/**
		表示方法之前执行
	*/
	@Override
	public boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handler)
		throws Exception{
		
		String method = request.getMethod();
		if("OPTIONS".equals(method)){ //如果是跨域预检请求,直接放行
			return true;
		}

		//获取token
		String token = request.getHeader("token");
		if(StrUtil.isEmpty(token)){
			responseNoLoginInfo(response);
			return false;
		}

		//如果token不为空,此时验证token的合法性
		String sysUserInfoJson = redisTemplate.opsForValue().get("user:ogin:"+token);
		if(strUtil.isEmpty(sysUserInfoJson)){
			responseNoLoginInfo(response);
			return false;
		}

		//将用户数据存储到ThreadLocal中
		SysUser sysUser = JSON.parseObject(sysUserInfoJson,SysUser.class);
		AuthContextUtil.set(sysUser);

		//重置redis中的有效时间
		redisTemplate.expire("user:login:" + token,30,TimeUnit.MINUTES);
		
		return true;
	}

	@Override
	public void afterCompletion(HttpServletRequest request,HttpServletResponse response,Object handler,Exception ex){
		AuthContextUtil.remove();
	}

	/**
		响应208状态码给前端
	*/
	private void responseNoLoginInfo(HttpServietResponse response){
		
		Result<Object> result = Result.build(null,ResultCodeEnum.LOGIN_AUTH);
		PrintWriter writer = null;

		response.setCharacterEncoding("UTF-8");
		response.setContentType("text/html;charset=utf8");
		try{
			writer = response.getWriter();
			writer.print(JSON.toJSONString(result));
		}catch(IOException e){
			e.printStackTrace();
		}finally{
			if(writer!=null){
				writer.close();
			}
		}
	}
}

③、拦截器注册

@Component
public class WebMvcConfiguration implements WebMvcConfigurer{
	
	// 注入拦截器
	@Autowired
	private LoginAuthInterceptor loginAuthInterceptor;

	/**
		拦截器注册
		对于以下多路径的筛选,可以通过配置文件的方式
	*/ 
	@Override
	public void addInterceptors(InterceptorRegistry registry){
		registry.addIntercepor(loginAutInterceptor)
			.excludePathPatterns("/admin/system/index/login","/admin/system/idenx/generateValidateCode")
			.addPathPatterns("/**");
	}
	
	/**
		addCorsMappings方法解决跨域问题
	*/
	@Override
	public void addCorsMappings(CorsRegistry registry){
		registry.addMapping("/**") //添加路径规则
			.allowCredentials(true) //是否允许在跨域的情况下传递Cookie
			.allowedOriginPatterns("*") //允许请求来源的域规则
			.allowedMethods("*")
			.allowedHeaders("*");
	}
}

登录校验的优化

将多路径的筛选,放置到配置配置文件

①、application-dev.yml

spzx:
	auth:
		noAuthUrls:
			- /admin/system/index/login
			- /admin/system/index/generateValidateCode

②、实体类定义

@Data
@ConfigurationProperties(prefix="spzx.auth")
public class UserAuthProperties{
	
	private List<String> noAuthUrls;
}

③、启动类添加注解:@EnableConfigurationProperties(value={UserAuthProperties.class})

④、注册拦截器代码的修改

@Autowired
private UserProperties userProperties;

@Override
public void addInterceptors(InterceptorRegistry registry){
	registry.addInterceptor(loginAuthInterceptor)
		.excludePathPatterns(userProperties.getNoAuthUrls())//优化后的代码
		.addPathPatterns("/**");
}

==================================================================

拦截器Interceptor实现登录校验_第1张图片

配置类

@Configuration
public class WebMvcConfig implements WebMvcConfigurer{
	
	@Override
	public void addInterceptors(InterceptorRegistry registry){//org.springframework:spring-webmvc:5.3.24
		
		registry.addInterceptor(new MyLoginInterceptor());
	}
}

拦截器

//登录拦截器
@Slf4j
public class MyLoginIntercpetor implements HandlerInterceptor{
	
	private static final String LOGIN_PATH = "user/login";
	
	private static Map<String,AtomicInteger> visitCount;
	private static final QQWry;

	static{
		visitCount = new HashMap<>(31);
		qqWry = new QQWry();
	}

	//展示访问数量不是精确指标,如果要做到完全正确需要使用锁,防止计数存在并发问题
	@Override
	public boolean preHandler(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception{
		
		log.info("【MyLoginInterceptor】调用了:{}", request.getRequestURI());
		if (request.getRequestURI().equals(LOGIN_PATH)) {
            String ipAddress = IPUtil.getIpAddress(request);
            String province = qqWry.findIP(ipAddress).getMainInfo();
            if (visitCount.containsKey(province)) {
                visitCount.put(province,new AtomicInteger(visitCount.get(province).incrementAndGet()));
            } else {
                visitCount.put(province,new AtomicInteger());
            }
        }
		return true;
	}

	@Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler, ModelAndView modelAndView) throws Exception {}

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object handler, Exception ex){}
}

IPUtil工具类

public class IPUtil {
    public static String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}

QQWry

public class QQWry {

    private static class QIndex {
        public final long minIP;
        public final long maxIP;
        public final int recordOffset;

        public QIndex(final long minIP, final long maxIP, final int recordOffset) {
            this.minIP = minIP;
            this.maxIP = maxIP;
            this.recordOffset = recordOffset;
        }
    }

    private static class QString {
        public final String string;
        /** length including the \0 end byte */
        public final int length;

        public QString(final String string, final int length) {
            this.string = string;
            this.length = length;
        }
    }

    private static final int INDEX_RECORD_LENGTH = 7;
    private static final byte REDIRECT_MODE_1 = 0x01;
    private static final byte REDIRECT_MODE_2 = 0x02;
    private static final byte STRING_END = '\0';

    private final byte[] data;
    private final long indexHead;
    private final long indexTail;

    /**
     * Create QQWry by loading qqwry.dat from classpath.
     *
     * @throws IOException
     *             if encounter error while reading qqwry.dat
     */
    public QQWry()  {
        InputStream in = QQWry.class.getClassLoader().getResourceAsStream("qqwry.dat");
        ByteArrayOutputStream out = new ByteArrayOutputStream(10 * 1024 * 1024); // 10MB
        byte[] buffer = new byte[4096];
        while (true) {
            int r = 0;
            try {
                r = in.read(buffer);
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (r == -1) {
                break;
            }
            out.write(buffer, 0, r);
        }
        data = out.toByteArray();
        indexHead = readLong32(0);
        indexTail = readLong32(4);
    }

    public IPZone findIP(final String ip) {
        final long ipNum = toNumericIP(ip);
        final QIndex idx = searchIndex(ipNum);
        if (idx == null) {
            return new IPZone(ip);
        }
        return readIP(ip, idx);
    }

    private long getMiddleOffset(final long begin, final long end) {
        long records = (end - begin) / INDEX_RECORD_LENGTH;
        records >>= 1;
        if (records == 0) {
            records = 1;
        }
        return begin + (records * INDEX_RECORD_LENGTH);
    }

    private QIndex readIndex(final int offset) {
        final long min = readLong32(offset);
        final int record = readInt24(offset + 4);
        final long max = readLong32(record);
        return new QIndex(min, max, record);
    }

    private int readInt24(final int offset) {
        int v = data[offset] & 0xFF;
        v |= ((data[offset + 1] << 8) & 0xFF00);
        v |= ((data[offset + 2] << 16) & 0xFF0000);
        return v;
    }

    private IPZone readIP(final String ip, final QIndex idx) {
        final int pos = idx.recordOffset + 4; // skip ip
        final byte mode = data[pos];
        final IPZone z = new IPZone(ip);
        if (mode == REDIRECT_MODE_1) {
            final int offset = readInt24(pos + 1);
            if (data[offset] == REDIRECT_MODE_2) {
                readMode2(z, offset);
            } else {
                final QString mainInfo = readString(offset);
                final String subInfo = readSubInfo(offset + mainInfo.length);
                z.setMainInfo(mainInfo.string);
                z.setSubInfo(subInfo);
            }
        } else if (mode == REDIRECT_MODE_2) {
            readMode2(z, pos);
        } else {
            final QString mainInfo = readString(pos);
            final String subInfo = readSubInfo(pos + mainInfo.length);
            z.setMainInfo(mainInfo.string);
            z.setSubInfo(subInfo);
        }
        return z;
    }

    private long readLong32(final int offset) {
        long v = data[offset] & 0xFFL;
        v |= (data[offset + 1] << 8L) & 0xFF00L;
        v |= ((data[offset + 2] << 16L) & 0xFF0000L);
        v |= ((data[offset + 3] << 24L) & 0xFF000000L);
        return v;
    }

    private void readMode2(final IPZone z, final int offset) {
        final int mainInfoOffset = readInt24(offset + 1);
        final String main = readString(mainInfoOffset).string;
        final String sub = readSubInfo(offset + 4);
        z.setMainInfo(main);
        z.setSubInfo(sub);
    }

    private QString readString(final int offset) {
        int i = 0;
        final byte[] buf = new byte[128];
        for (;; i++) {
            final byte b = data[offset + i];
            if (STRING_END == b) {
                break;
            }
            buf[i] = b;
        }
        try {
            return new QString(new String(buf, 0, i, "GB18030"), i + 1);
        } catch (final UnsupportedEncodingException e) {
            return new QString("", 0);
        }
    }

    private String readSubInfo(final int offset) {
        final byte b = data[offset];
        if ((b == REDIRECT_MODE_1) || (b == REDIRECT_MODE_2)) {
            final int areaOffset = readInt24(offset + 1);
            if (areaOffset == 0) {
                return "";
            } else {
                return readString(areaOffset).string;
            }
        } else {
            return readString(offset).string;
        }
    }

    private QIndex searchIndex(long ip) {
        long head = indexHead;
        long tail = indexTail;
        while (tail > head) {
            final long cur = getMiddleOffset(head, tail);
            final QIndex idx = readIndex((int) cur);
            if ((ip >= idx.minIP) && (ip <= idx.maxIP)) {
                return idx;
            }
            if ((cur == head) || (cur == tail)) {
                return idx;
            }
            if (ip < idx.minIP) {
                tail = cur;
            } else if (ip > idx.maxIP) {
                head = cur;
            } else {
                return idx;
            }
        }
        return null;
    }

    /**
     * ip从字符串转为long类型
     * @param str
     * @return res
     */
    private long toNumericIP(String str) {
       String[] splits = str.split("\\.");
        if (4 != splits.length) {
            throw new IllegalArgumentException("ip格式异常,请检查后重试");
        }
        long res = Long.parseLong(splits[0]) << 24L;
        res += Long.parseLong(splits[1]) << 16L;
        res += Long.parseLong(splits[2]) << 8L;
        res += Long.parseLong(splits[3]);
        return res;
    }
}

IPZone

public class IPZone {
    private final String ip;
    private String mainInfo = "";
    private String subInfo = "";

    public IPZone(final String ip) {
        this.ip = ip;
    }

    public String getIp() {
        return ip;
    }

    public String getMainInfo() {
        if (mainInfo.contains("省")) {
            return mainInfo.substring(0,mainInfo.indexOf("省"));
        }
        if (mainInfo.contains("市")) {
            return mainInfo.substring(0,mainInfo.indexOf("市"));
        }
        return mainInfo;
    }

    public String getSubInfo() {
        return subInfo;
    }

    public void setMainInfo(final String info) {
        this.mainInfo = info;
    }

    public void setSubInfo(final String info) {
        this.subInfo = info;
    }

    @Override
    public String toString() {
        return new StringBuilder(mainInfo).append(subInfo).toString();
    }

}

你可能感兴趣的:(拦截器Interceptor,登录校验,ThreadLocal)