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

