概述
前端页面中要设计埋点,用来收集用户的行为习惯等信息以便进行实时流计算,从而提高系统的安全性。如:登录风险评估
等。
本篇简单介绍了一个登录输入时长
检查的埋点的设计。
引入Cookic
引入cookic
,目的是为了,我们可以将在页面定制的一些采集的数据,通过请求发送的形式,携带到服务器端。
①引入cookic插件
将下面的文本Copy到自定义的一个**
.js
**结尾的文件中, 完成cookic插件的引入。
例:jquery.cookic.min.js
/*! jquery.cookie v1.4.1 | MIT */
!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?a(require("jquery")):a(jQuery)}(function(a){function b(a){return h.raw?a:encodeURIComponent(a)}function c(a){return h.raw?a:decodeURIComponent(a)}function d(a){return b(h.json?JSON.stringify(a):String(a))}function e(a){0===a.indexOf('"')&&(a=a.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\/g,"\\"));try{return a=decodeURIComponent(a.replace(g," ")),h.json?JSON.parse(a):a}catch(b){}}function f(b,c){var d=h.raw?b:e(b);return a.isFunction(c)?c(d):d}var g=/\+/g,h=a.cookie=function(e,g,i){if(void 0!==g&&!a.isFunction(g)){if(i=a.extend({},h.defaults,i),"number"==typeof i.expires){var j=i.expires,k=i.expires=new Date;k.setTime(+k+864e5*j)}return document.cookie=[b(e),"=",d(g),i.expires?"; expires="+i.expires.toUTCString():"",i.path?"; path="+i.path:"",i.domain?"; domain="+i.domain:"",i.secure?"; secure":""].join("")}for(var l=e?void 0:{},m=document.cookie?document.cookie.split("; "):[],n=0,o=m.length;o>n;n++){var p=m[n].split("="),q=c(p.shift()),r=p.join("=");if(e&&e===q){l=f(r,g);break}e||void 0===(r=f(r))||(l[q]=r)}return l};h.defaults={},a.removeCookie=function(b,c){return void 0===a.cookie(b)?!1:(a.cookie(b,"",a.extend({},c,{expires:-1})),!a.cookie(b))}});
②声明插件的引用
<script type="text/javascript" src="/static/common/jquery.cookic.min.js"></script>
设计埋点
①定义埋点
$.fn.extend({
inputFeatures: function () {//收集用户的表单输入特征
var inputs = $(this).find("input")
//定义一个特性集合
var futuresMap = {}
$.each(inputs, function (i, item) {
$(item).bind("keydown", function (event) {
//如果已经有起始时间就采用原来的起始时间
var start = $(this).data("start")
//如果时间是空的
if (!start) {
var start = new Date().getTime();//按下去记一次start
$(this).data("start", start)
}
})
$(item).bind("keyup", function (event) {
var end = new Date().getTime();//弹起去记一次end
var start = $(this).data("start")
//如果当前输入框中无值
if ($(this).val() == "") {
//将时间start置为null
$(this).data("start", null)
//这个特性的数组置为0
futuresMap[i] = 0
} else {
futuresMap[i] = end - start
}
//定义一个数组
var keys = []
for (var k in futuresMap) {
keys.push(k)
}
//对key进行排序
var sortedKeys = keys.sort();
//获取表单输入特征
var feature = sortedKeys.map(key=>futuresMap[key])
/* console.log(feature.join(","))*/
//存放到会话cookic中 //设置全局可访问此cookic
$.cookie("feature",feature.join(","),{path:'/'})
})
})
}
})
②声明使用埋点
<script>
//设置一个定时器,给当前的输入绑定一个输入特性采集
setTimeout(function(){
$("#user_login_form").inputFeatures()
},1000)
})
</script>
<form id="user_login_form" method="post">
.
.
.
</form>ss
控制层接收埋点
这里的接收埋点信息,此次项目放在了拦截器中进行处理。
①定义拦截器
package com.baizhi.interceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
//将此组件交给工厂
@Component
public class UserInputFeatureInterceptor implements HandlerInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(UserInputFeatureInterceptor.class);
@Autowired
private RestTemplate restTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//从请求中,获取cookic
Cookie[] cookies = request.getCookies();
/* LOGGER.info("COOKIS长度\t"+cookies.length);
for (Cookie cookie : cookies) {
LOGGER.info(cookie.getName());
}*/
//定义一cookic值引用
String inputFeature=null;
//遍历cookics,取出名为“feature”的cookic
for (Cookie cookie : cookies) {
if("feature".equals(cookie.getName())){
inputFeature = URLDecoder.decode(cookie.getValue());
//跳出循环
break;
}
}
//定义一处理ip的请求头
String url = "http://ip-api.com/json/?ip={ip}";
HashMap<String, Object> map = new HashMap<>();
map.put("ip","123.149.125.171");
Map ipParse = restTemplate.getForObject(url, Map.class, map);
//获取信息
String name = request.getParameter("name");
String password = request.getParameter("password");
//获取ip地址
String ip = request.getRemoteAddr();
//获取头信息
String agent = request.getHeader("User-Agent");
LOGGER.info("请求参数为\t"+name+"\t"+password+"\tip地址:"+ipParse+"\t请求头:"+agent+"\t输入特性是:"+inputFeature);
/*2020-03-29 15:56:35.783 INFO 12620 --- [nio-9999-exec-8] c.b.i.UserInputFeatureInterceptor : 请求参数为 测试数据2 000000 ip地址:{status=success, country=China, countryCode=CN, region=HA, regionName=Henan, city=Yingchuan, zip=, lat=34.2904, lon=113.382, timezone=Asia/Shanghai, isp=Chinanet, org=Chinanet HA, as=AS4134 Chinanet, query=123.149.125.171} 请求头:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36 输入特性是:2718,7472,1612
*/
return true;
}
}
②配置拦截器
package com.baizhi.interceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
//配置拦截器属性,使拦截器生效
@Configuration
class RealInerceptor implements WebMvcConfigurer {
//注入自定义拦截器
@Autowired
UserInterceptor userInterceptor;
@Autowired
UserInputFeatureInterceptor userInputFeatureInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(userInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/static/**")
.excludePathPatterns("/work/login/**")
.excludePathPatterns("/user/loginCheck")
.excludePathPatterns("/user/session")
.excludePathPatterns("/user/existsUser")
.excludePathPatterns("/user/zhuce")
.excludePathPatterns("/code/**");
//添加用户输入特征的拦截器
registry.addInterceptor(userInputFeatureInterceptor)
//拦截
.addPathPatterns("/user/loginCheck");
}
}