ajax 访问--提高安全性

首先受到struts token的启发,产生了客户端发起的ajax请求进行验证的想法,大致思路是客户端每次请求产生一个key ,然后服务端接收到key,然后解析,判断是否为合法key, 对于不带key 或者验证失败的直接拦截下来,从而减轻服务器的压力,好了废话不多说,上代码

首先我使用的是struts2的拦截器,(ps:不知道的度娘告诉你)

继承 AbstractInterceptor 实现init()和 intercept() ,从字面意思上去理解这两个方法 初始化 和拦截

第一个方法 就是从配置文件读取配置信息,没什么特别的

第二个方法 主要是分为两部分验证key 我这里 分 ajax 访问和普通方法 看代码 

public String intercept(ActionInvocation invocation) throws Exception {
        String rs = null;
        if (isTokenInterceptor) {
            boolean flag = false;
            String msg = "{_success : false,_operationMsg:'非正常访问,属于非法客户端!'}";
            ActionContext ac = invocation.getInvocationContext();
            HttpServletRequest request = (HttpServletRequest) ac.get("com.opensymphony.xwork2.dispatcher.HttpServletRequest");
            if (PublicUtil.isNotEmpty(freeURL)) {
                String urlValue[] = freeURL.split(",");
                if (PublicUtil.isNotEmpty(urlValue)) {
                    String as[];
                    int j = (as = urlValue).length;
                    for (int i = 0; i < j; i++) {
                        String url = as[i];
                        if (request.getRequestURI().indexOf(url) != -1) {
                            flag = true;
                            break;
                        }
                    }
                }
            } 
            if(!flag){
                HttpSession session = request.getSession();
                String requestToken;
                HttpServletResponse response;
                try {
                    response = (HttpServletResponse) ac.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse");
                    String requestType = request.getHeader("X-Requested-With");
                    if("XMLHttpRequest".equals(requestType)){ //验证是否为ajax 请求
                        requestToken = request.getHeader(TOKEN_NAME);
                        if(PublicUtil.isNotEmpty(requestToken) && requestToken.indexOf("||")!=-1){
                            String token = (String) session.getAttribute(SESSION_TOKEN);
                            if (!requestToken.equals(token)) {
                                flag = true;
                            } else {
                                logger.warn(PublicUtil.toAppendStr(
                                        "客户端表单防重复验证生效:客户端多次提交 requestToken:",
                                        requestToken));
                                msg = "{_success : false,_operationMsg : '对不起,网络异常,请重新提交尝试!'}";
                            }
                            session.setAttribute(SESSION_TOKEN, requestToken);
                        }
                    }else{ //普通请求 通过读取cookie 来验证
                        requestToken = CookieUtil.getCookie(request, TOKEN_NAME);
                        if(PublicUtil.isEmpty(requestToken)){
                            requestToken = DesUtil.getRequestKey();
                        }
                        if(PublicUtil.match("^[0-9]{8}$", DesUtil.strDec(requestToken))){
                            String token = (String) session.getAttribute(COOKIE_TOKEN);
                            if(PublicUtil.isEmpty(token)){
                                token = requestToken;
                            }
                            if (requestToken.equals(token)) {
                                flag = true;
                            } else {
                                logger.warn(PublicUtil.toAppendStr(
                                        "客户端表单防重复验证生效:客户端多次提交 requestToken:",
                                        requestToken, " url:", request.getRequestURI()));
                                msg = "{_success : false,_operationMsg : '对不起,网络异常,请重新提交尝试!'}";
                            }
                        }
                        String nextToken = DesUtil.getRequestKey();
                        CookieUtil.setCookie(response, TOKEN_NAME, nextToken);
                        session.setAttribute(COOKIE_TOKEN, nextToken);
                        flag = true;
                    }
                } catch (IllegalStateException e) {
                    flag = false;
                    msg = PublicUtil.toAppendStr(
                            "{_success : false,_operationMsg : 'Error creating HttpSession due response is commited to client. You can use the CreateSessionInterceptor or create the HttpSession from your action before the result is rendered to the client: ",
                                    e.getMessage(), "'}");
                    e.printStackTrace();
                }
            }
            if (flag) {
                rs = invocation.invoke();
            } else {
                HttpServletResponse response = (HttpServletResponse) ac
                        .get("com.opensymphony.xwork2.dispatcher.HttpServletResponse");
                response.setCharacterEncoding("UTF-8");
                response.getWriter().write(msg);
            }
        } else {
            rs = invocation.invoke();
        }
        return rs;
    }

前台, 对于ajax 提交,我采用的header 夹带验证key的方式进行传递, 因为项目中使用的jquery 所以 我直接重写 $.ajax 方法就搞定了

var TOKEN_NAME = "Albedo-Requst-Token";
(function($){
    //备份jquery的ajax方法
    var _ajax=$.ajax;
    
    //重写jquery的ajax方法
    $.ajax=function(opt){
        //备份opt中error和success方法
        var fn = {
            error:function(XMLHttpRequest, textStatus, errorThrown){},
            success:function(data, textStatus){}
        }
        if(opt.error){
            fn.error=opt.error;
        }
        if(opt.success){
            fn.success=opt.success;
        }
        
        //扩展增强处理
        var _opt = $.extend(opt,{
            beforeSend: function(request) {
                request.setRequestHeader("Albedo-Requst-Token", getRequestKey()+"||"+opt.url); //产生一个时间不同时的唯一key 特别注意 时间不同,如果时间相同,可以应该一样
            },
            error:function(XMLHttpRequest, textStatus, errorThrown){
                //错误方法增强处理
                fn.error(XMLHttpRequest, textStatus, errorThrown);
            },
            success:function(data, textStatus){
                //成功回调方法增强处理
                if(typeof data=="string"){ //对于被拦截下来的请求统一做提示
                    try{
                        eval("var rs = " + data);
                        if(rs && rs._success == false && rs._operationMsg){
                            if(!g_showTip) alert(rs._operationMsg);
                            else setTimeout(function(){g_showTip(rs._operationMsg);},500);
                        }
                    }catch(e){}
                }
                fn.success(data, textStatus);
            }
        });
        _ajax(_opt);
    };
})(jQuery);

当然,没有用这个的,也不要跪,至少还有?后面传参也是可以搞定的 ^_^, 

这样之后就搞定了,如果一个页面连续对一个地址发起几次请求,那么这样之后只会有第一个请求成功,之后的请求全部会被拦截下来

ps: 个人见解,有不足之处,可以提出来大家参考

原文地址:https://www.cnblogs.com/lljj/p/3849103.html