下发短信功能的实现,卡洛思接口的使用,
因为公司的业务需要调用短信下发第三方接口,实现短信下发功能的开发。
这里选取的第三方接口是卡洛思接口,短信接口有很多,不同的接口实现的方式有一天区别。
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; }
对于短信的下发此时的保护,还可以有多种方式,比如下发短信的时候,输入图形验证码,控制用户的下发时间,可以减少访问次数,
或者说当达到一定的次数,直接限制不能下发短信,
或许还可以有很多的方式,对于真正的安全防范,这种小儿科的措施肯定是不起作用的,也就是防范某些小白的操作罢了
或许你也有更多的方案呢。
