下發短信功能的實現,卡洛思接口的使用,
因為公司的業務需要調用短信下發第三方接口,實現短信下發功能的開發。
這裏選取的第三方接口是卡洛思接口,短信接口有很多,不同的接口實現的方式有一天區別。
卡洛思接口,直接調用一下它封裝好的方法就可以實現了,因此這部分其實不太需要花精力去關註。
項目的部分,因為考慮到需要防止惡意用戶故意去網站下發短信,所以需要做一些安全的防護,
所以這部分內容重點還是放在了關於短信模板中一個短連接的生成,以及安全防護的設計上了。
關於卡洛思平臺的接口文檔,跟它封裝好的案例代碼,可以到下面這個網站去取
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"); }
處理完基本的短信部分,接下來講一些一開始的短信安全防範思路,也是一開始的思路,比較簡單的一種處理方式
就是對客戶提交的手機號的同時,可以獲取客戶的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; }
對於短信的下發此時的保護,還可以有多種方式,比如下發短信的時候,輸入圖形驗證碼,控制用戶的下發時間,可以減少訪問次數,
或者說當達到一定的次數,直接限制不能下發短信,
或許還可以有很多的方式,對於真正的安全防範,這種小兒科的措施肯定是不起作用的,也就是防範某些小白的操作罷了
或許你也有更多的方案呢。
下發短信功能的實現,卡洛思接口的使用,