因为公司的业务需要调用短信下发第三方接口,实现短信下发功能的开发。

这里选取的第三方接口是卡洛思接口,短信接口有很多,不同的接口实现的方式有一天区别。

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

卡洛思接口,直接调用一下它封装好的方法就可以实现了,因此这部分其实不太需要花精力去关注。

项目的部分,因为考虑到需要防止恶意用户故意去网站下发短信,所以需要做一些安全的防护,

所以这部分内容重点还是放在了关于短信模板中一个短连接的生成,以及安全防护的设计上了。

关于卡洛思平台的接口文档,跟它封装好的案例代码,可以到下面这个网站去取

http://118.31.17.45:8899/Index.aspx   

需要注册的信息,就需要用户自己去注册一个账号了,到时候代码开发会用到的。

基本的短信下发调用代码如下

    public static String url1 = "http://118.31.17.45:8899/sms.aspx";  //请求接口,
    public static String userss = "2341";            //企业ID固定的
    public static String account = "你的个人账户";  //平台账户
    public static String password = "你的个人密码";      //平台密码

   然后配置完了以后,
   String msg = SmsClientSend.sendSms(url1, userss, account,
                password, phone, content);
    直接调用下发短信的接口就可以了,其中phone是要发送过去的手机号码,
    content是短信模板,其中模板需要公司的签名为前缀,比如
   【XX公司标志】尊敬的客户,你好!

 其中,由于短信模板里面带有一个短连接,为了防止短信字数多长,需要对原始的链接进行重新跳转的处理,

因此将原始的长链接转换为短连接发送,这里短连接一般是固定的位数的,根据一定的算法进行重整生成。

这里使用了一个微博的短连接生成接口,

http://api.weibo.com/2/short_url/shorten.json?source=2849184197&url_long=【你的请求域名】?parameter=value

只要在短连接第三方生成接口里面加上你原本链接的请求域名,以及你要传递的参数就可以生成新的短连接了。

我在开发的时候,对于短连接的返回的内容

 下发短信功能的实现,卡洛思接口的使用, 随笔

需要提取的短连接部分是 url_short部分,不过因为返回的格式一开始是有问题的,不是标准的json格式,

所以,需要对返回的数据进行一定的切割提取。

下面是切割提取短连接的代码片段

 

/**
     * 生成短连接
     * @param user 附带userid参数,你可以根据需要附带你想要传递的参数
     * @return
     */
    public String cutLink(User user){
        JSONObject jsonobj  = null;
        SmsController link = new SmsController();
        String url = "http://api.weibo.com/2/short_url/shorten.json?source=2849184197&" +
                "url_long=【替换为你的域名】?userId="+user.getUserid();
        try {
            String jsonString = link.sendGet(url);  //这里请求回接口的返回数据
            System.out.println("****"+jsonString+"****");
            jsonobj = JSONObject.parseObject(jsonString);
            String r  = jsonobj.getString("urls");    //获取返回的数据里的urls部分,
            System.out.println(r);
            r=r.replace("[", "");
            r=r.replace("]", "");  //去掉最外层的[]括号,获取json的标准格式 
            jsonobj =JSONObject.parseObject(r);
            System.out.println(jsonobj.getString("url_short"));   //最后才获取url_short短链接
        } catch (Exception e) {
            System.out.printf(e.toString());
        }
        return jsonobj.getString("url_short");
    }

/**
* 模拟发起get请求
* @param apiLink
* @return
* @throws Exception
*/
public String sendGet(String apiLink) throws Exception {
StringBuffer sb = new StringBuffer();
URL url = new URL(apiLink);
InputStreamReader isr = new InputStreamReader(url.openStream());
char[] buffer = new char[1];
while (isr.read(buffer) != -1) {
sb.append(buffer);
}
isr.close();
return sb.toString();
}

处理完基本的短信部分,接下来讲一些一开始的短信安全防范思路,也是一开始的思路,比较简单的一种处理方式

就是对客户提交的手机号的同时,可以获取客户的cookie,ip,手机号信息,

为了方式客户多次提交,以及防止不良用户的故意多次刷短信,

需要对每次的次数进行限制,这里的限制可以根据每个人的需要去设计。

比如说对对方的IP在某个时间段内限制访问30次,同时该手机最多不能超过5次访问。

这个感觉也是要根据实际的业务需求去进行更改的。

限制次数代码

        //根据接收的request获取ip
        ServletRequestAttributes attr=(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request =attr.getRequest();

        String ip = getIpAddr(request);

        //IpTime 保存了每一个Ip的访问次数,访问时间
        Iptime iptime = iptimeService.getIpTimes(ip); 
        
       //开始判断用户的访问次数,这一部分就是数据库业务逻辑了
       if(iptime == null){
            Iptime tempiptime = new Iptime();
            tempiptime.setIptime(1);
            tempiptime.setIp(ip);
            tempiptime.setDeadtime(addDateMinut(1));
            if(user!=null)
                tempiptime.setUserid(user.getUserid());
            int insertflag = iptimeService.insert(tempiptime);
            if(insertflag>0){
                System.out.println("第一次访问,新建iptime成功");
            }
        }
        if(iptime!=null){
            if(iptime.getIptime()>30){
                String deadline = iptime.getDeadtime(); //获取限制30次时间以内的截止时间
                java.text.SimpleDateFormat formatter = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss");
                Date date = formatter.parse(deadline);
                Date now = new Date();
                if(now.getTime() < date.getTime()) {  //1个小时以内超过30次
                    System.out.println("11");
                    map.put("status", "0");
                    map.put("message", "ip次数访问超过30次了!");
                    Phonedate phonedate = new Phonedate();
                    phonedate.setPhone(phone);
                    phonedate.setRecordtime(new Date());
                    int flag = phonedateService.insertPhonedate(phonedate);
                    if (flag > 0) {
                        System.out.println("保存好不符合的手机号了");
                    }
                    user.setAddtime(new java.sql.Date(new Date().getTime()));
                    userService.updateUser(user);
                    return callback + "(" + gson.toJson(map) + ")";
                }else{
                    iptime.setIptime(1);
                    iptime.setDeadtime(addDateMinut(1));
                    int insertflag = iptimeService.updateIptime(iptime);

                    if(insertflag>0){
                        System.out.println("时间超过了1小时了,次数变成1,时间从此刻开始计算");
                    }
                }
            }else{
                //没有保存超过30次的,
                System.out.println("12");
                iptime.setIptime(iptime.getIptime()+1);
                int updateflag =iptimeService.updateIptime(iptime);
                if(updateflag>0){
                    System.out.println("更新成功了!");
                }
                String deadline = iptime.getDeadtime(); //获取限制30次时间以内的截止时间
                java.text.SimpleDateFormat formatter = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss");
                Date date = formatter.parse(deadline);
                Date now = new Date();
                if(now.getTime() > date.getTime()){
                    iptime.setIptime(1);
                    iptime.setDeadtime(addDateMinut(1));
                    int insertflag = iptimeService.updateIptime(iptime);
                    if(insertflag>0){
                        System.out.println("ip访问次数因为时间过了,次数变成1,重新开始计算,并且时间此刻开始计算");
                    }
                }
            }
        }
        Phonetime phonetime = phonetimeService.getPhoneTimes(phone);
        if(phonetime==null){
            Phonetime tempPhonetime = new Phonetime();
            tempPhonetime.setPhone(phone);
            tempPhonetime.setPhonetime(1);
            if(user!=null)
                tempPhonetime.setUserid(user.getUserid());
            int phoneFlag = phonetimeService.insert(tempPhonetime);  //这时候插入,需要手机号有对应的用户才可以
            if(phoneFlag >0) {
                System.out.println("新建phoneFlag成功了");
            }
        }
        System.out.println("2");
        if(phonetime!=null){
            if(phonetime.getPhonetime()>=5){
                System.out.println("21");
                map.put("status","0");
                map.put("message","手机号次数访问超过5次了!");
                Phonedate phonedate = new Phonedate();
                phonedate.setPhone(phone);
                phonedate.setRecordtime(new Date());
                int flag = phonedateService.insertPhonedate(phonedate);
                if(flag>0){
                    System.out.println("保存好不符合的手机号了");
                }
                user.setAddtime(new java.sql.Date(new Date().getTime()));
                userService.updateUser(user);
                return callback+"("+gson.toJson(map)+")";
            }else{
                System.out.println("22");
                //没有超过5次的,
                phonetime.setPhonetime(phonetime.getPhonetime()+1);
                int phonetimeflag = phonetimeService.updatePhonetime(phonetime);
                if(phonetimeflag>0){
                    System.out.println("更新成功了!");
                }
            }
        }

        
    //获取当前X小时候后的时间,String格式
     public static String addDateMinut(int hour){
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date();
        if (date == null)
            return "";
        System.out.println("front:" + format.format(date)); //显示输入的日期
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.HOUR, hour);// 24小时制
        date = cal.getTime();
        System.out.println("after:" + format.format(date));  //显示更新后的日期
        cal = null;
        return format.format(date);

    }

        /**
     * 获取客户端IP
     * @param request
     * @return
     */
    private String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");

        System.out.println("x-forwarded-for ip: " + ip);
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个ip值,第一个ip才是真实ip
            if( ip.indexOf(",")!=-1 ){
                ip = ip.split(",")[0];
            }
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
            System.out.println("Proxy-Client-IP ip: " + ip);
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
            System.out.println("WL-Proxy-Client-IP ip: " + ip);
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
            System.out.println("HTTP_CLIENT_IP ip: " + ip);
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            System.out.println("HTTP_X_FORWARDED_FOR ip: " + ip);
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
            System.out.println("X-Real-IP ip: " + ip);
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
            System.out.println("getRemoteAddr ip: " + ip);
        }
        System.out.println("获取客户端ip: " + ip);
        return ip;
    }

对于短信的下发此时的保护,还可以有多种方式,比如下发短信的时候,输入图形验证码,控制用户的下发时间,可以减少访问次数,

或者说当达到一定的次数,直接限制不能下发短信,

或许还可以有很多的方式,对于真正的安全防范,这种小儿科的措施肯定是不起作用的,也就是防范某些小白的操作罢了

或许你也有更多的方案呢。

 

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄