Browse Source

添加行为验证

杨杰 6 years ago
parent
commit
ead662ee6b

+ 6 - 1
pom.xml

@@ -44,7 +44,12 @@
 		<dependency>
 			<groupId>com.aliyun</groupId>
 			<artifactId>aliyun-java-sdk-core</artifactId>
-			<version>4.1.0</version>
+			<version>4.4.2</version>
+		</dependency>
+		<dependency>
+			<groupId>com.aliyun</groupId>
+			<artifactId>aliyun-java-sdk-afs</artifactId>
+			<version>1.0.0</version>
 		</dependency>
 		<dependency>
 			<groupId>io.springfox</groupId>

+ 11 - 8
src/main/java/com/llisoft/service/sms/controller/SmsController.java

@@ -1,5 +1,6 @@
 package com.llisoft.service.sms.controller;
 
+import javax.servlet.http.HttpServletRequest;
 import javax.validation.Valid;
 
 import org.springframework.beans.factory.annotation.Autowired;
@@ -9,6 +10,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 import com.llisoft.common.exception.MtaException;
+import com.llisoft.common.util.ServletUtil;
 import com.llisoft.common.vo.ResponseVo;
 import com.llisoft.service.sms.service.SmsService;
 import com.llisoft.service.sms.vo.CheckCodeRequestVo;
@@ -17,9 +19,9 @@ import com.llisoft.service.sms.vo.SendCodeRequestVo;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 
-@Api(tags="短信接口")
+@Api(tags="短信")
 @RestController
-@RequestMapping("/msg")
+@RequestMapping("/sms")
 public class SmsController {
 	
 	@Autowired
@@ -28,14 +30,15 @@ public class SmsController {
 	
 	@ApiOperation(value="发送验证码")
 	@PostMapping("/sendCode")
-	public ResponseVo<Boolean> sendCode(@Valid @RequestBody SendCodeRequestVo vo) throws MtaException{
-		return ResponseVo.success(smsService.sendCode(vo.getPhone()));
+	public ResponseVo<Boolean> sendCode(@Valid @RequestBody SendCodeRequestVo vo, HttpServletRequest request) throws MtaException{
+		return ResponseVo.success(smsService.sendCode(vo.getPhone(), vo.getAppkey(), 
+			vo.getScene(), vo.getToken(), vo.getSessionid(), vo.getSid(), ServletUtil.getIp(request)));
 	}
 	
-	@ApiOperation(value="检查验证码")
-	@PostMapping("/checkCode")
-	public ResponseVo<Boolean> checkCode(@Valid @RequestBody CheckCodeRequestVo vo) throws MtaException{
-		return ResponseVo.success(smsService.checkCode(vo.getPhone(), vo.getCode()));
+	@ApiOperation(value="发送消息")
+	@PostMapping("/sendMsg")
+	public ResponseVo<Boolean> sendMsg(@Valid @RequestBody CheckCodeRequestVo vo) throws MtaException{
+		return ResponseVo.success(false);
 	}
 	
 }

+ 28 - 0
src/main/java/com/llisoft/service/sms/controller/feign/FeignSmsController.java

@@ -0,0 +1,28 @@
+package com.llisoft.service.sms.controller.feign;
+
+import javax.validation.Valid;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.llisoft.common.exception.MtaException;
+import com.llisoft.common.vo.ResponseVo;
+import com.llisoft.service.sms.service.SmsService;
+import com.llisoft.service.sms.vo.CheckCodeRequestVo;
+
+@RestController
+@RequestMapping("/feign/msg")
+public class FeignSmsController {
+	
+	@Autowired
+	private SmsService smsService;
+	
+	@PostMapping("/checkCode")
+	public ResponseVo<Boolean> checkCode(@Valid @RequestBody CheckCodeRequestVo vo) throws MtaException{
+		return ResponseVo.success(smsService.checkCode(vo.getPhone(), vo.getCode()));
+	}
+	
+}

+ 49 - 12
src/main/java/com/llisoft/service/sms/service/AliyunService.java

@@ -1,5 +1,7 @@
 package com.llisoft.service.sms.service;
 
+import java.util.Objects;
+
 import javax.annotation.PostConstruct;
 
 import org.slf4j.Logger;
@@ -12,8 +14,12 @@ import com.aliyuncs.CommonRequest;
 import com.aliyuncs.CommonResponse;
 import com.aliyuncs.DefaultAcsClient;
 import com.aliyuncs.IAcsClient;
+import com.aliyuncs.afs.model.v20180112.AuthenticateSigRequest;
+import com.aliyuncs.afs.model.v20180112.AuthenticateSigResponse;
+import com.aliyuncs.exceptions.ClientException;
 import com.aliyuncs.http.MethodType;
 import com.aliyuncs.profile.DefaultProfile;
+import com.llisoft.common.util.JsonUtil;
 
 /**
  * 阿里云SMS接口调用
@@ -32,12 +38,15 @@ public class AliyunService {
 	private String accessKeySecret;
 	
 	// API客户端
-	private IAcsClient client;
+	private IAcsClient smsClient;
+	private IAcsClient afsClient;
 	
 	@PostConstruct
 	public void init() { // 初始化
-		DefaultProfile profile = DefaultProfile.getProfile("default", accessKeyId, accessKeySecret);
-		client = new DefaultAcsClient(profile);
+		smsClient = new DefaultAcsClient(DefaultProfile.getProfile("default", accessKeyId, accessKeySecret));
+		String regionId = "cn-hangzhou"; // 验证码官方文档写死
+		DefaultProfile.addEndpoint(regionId, "afs", "afs.aliyuncs.com");
+		afsClient = new DefaultAcsClient(DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret));
 	}
 	
 	
@@ -47,25 +56,53 @@ public class AliyunService {
 	 * @param code
 	 */
 	@Async
-	public void sendCode(String phone, String code) {
+	public boolean sms(String phone, String code) {
 		logger.info("阿里云发送验证码: {} : {}", phone, code);
 		CommonRequest request = new CommonRequest();
-        //request.setProtocol(ProtocolType.HTTPS);
-        request.setMethod(MethodType.POST);
-        request.setAction("SendSms");
-        request.setDomain("dysmsapi.aliyuncs.com");
-        request.setVersion("2017-05-25"); // 固定字符串
+//        request.setSysProtocol(ProtocolType.HTTPS);
+        request.setSysMethod(MethodType.POST);
+        request.setSysAction("SendSms");
+        request.setSysDomain("dysmsapi.aliyuncs.com");
+        request.setSysVersion("2017-05-25"); // 固定字符串
         request.putQueryParameter("PhoneNumbers", phone);
         request.putQueryParameter("SignName", "大鱼测试"); // 签名
         request.putQueryParameter("TemplateCode", "SMS_6792308"); // 模板ID
         request.putQueryParameter("TemplateParam", "{\"customer\":\""+code+"\"}");
         try {
-            CommonResponse response = client.getCommonResponse(request);
-            logger.info("阿里云短信API返回: {}", response.getData());
+            CommonResponse response = smsClient.getCommonResponse(request);
+            logger.info("阿里云短信API返回: {}", JsonUtil.toJson(response));
+            return Objects.nonNull(response) && Objects.nonNull(response.getData());
         } catch (Exception e) {
         	logger.error("阿里云短信API异常", e);
         }
-	
+        return false;
 	}
+	
+	/**
+	 * 验证码
+	 * @param sessionId
+	 * @param sig
+	 * @param token
+	 * @param ip
+	 * @return
+	 * @throws ClientException
+	 */
+    public boolean afs(String appkey, String scene, String token, String sessionId, String sig, String ip) {
+        AuthenticateSigRequest request = new AuthenticateSigRequest();
+        request.setAppKey(appkey);// 应用类型标识。必填参数,后端填写。
+        request.setScene(scene);// 场景标识。必填参数,后端填写。
+        request.setToken(token);// 请求唯一标识。必填参数,从前端获取,不可更改。
+        request.setSessionId(sessionId);// 会话ID。必填参数,从前端获取,不可更改,android和ios只传这个参数即可
+        request.setSig(sig);// 签名串。必填参数,从前端获取,不可更改。
+        request.setRemoteIp(ip);// 客户端IP。必填参数,后端填写。
+        try { // response的code枚举:100验签通过,900验签失败
+            AuthenticateSigResponse response = afsClient.getAcsResponse(request);
+            logger.info("阿里云验证码API返回: {}", JsonUtil.toJson(response));
+            return Objects.nonNull(response) && response.getCode()==100;
+        } catch (Exception e) {
+        	logger.error("阿里云验证码API异常", e);       
+        }
+        return false;
+    }
 
 }

+ 32 - 8
src/main/java/com/llisoft/service/sms/service/SmsService.java

@@ -8,6 +8,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import com.llisoft.common.exception.MtaException;
 import com.llisoft.common.util.RandomUtil;
 import com.llisoft.service.sms.util.RedisUtil;
 
@@ -28,9 +29,36 @@ public class SmsService {
 	 * 发送验证码
 	 * 同手机号 每分钟1条/每小时5条/每天10条
 	 * @param phone
+	 * @throws MtaException 
 	 */
-	public boolean sendCode(String phone) {
-		logger.info("发送验证码: {}", phone);
+	public boolean sendCode(String phone, String appkey, String scene, 
+			String token, String sessionId, String sig, String ip) throws MtaException {
+		// 检查验证码
+		logger.info("安全验证: token={},ip={}", phone, ip);
+		if (!aliyunService.afs(appkey, scene, token, sessionId, sig, ip)) {
+			logger.warn("安全验证失败:{}", token);
+			throw new MtaException("安全验证失败:" + token);
+		}
+		// 检查号码
+		logger.info("检查手机号: {}", phone);
+		if(!this.checkSend(phone)) {
+			logger.warn("手机号被限制发送:{}", phone);
+			throw new MtaException("此号码被限制发送:" + phone);
+		}
+		// 发送短信
+		String code = String.valueOf(RandomUtil.getRandomInt(4));
+		RedisUtil.set(phone + "_" + code, "", 10, TimeUnit.MINUTES); // 有效期10分钟
+		logger.info("发送验证码: {}", code);
+		aliyunService.sms(phone, code); // 第三方发送短信
+		return true;
+	}
+	
+	/**
+	 * 检查发送
+	 * @param phone
+	 * @return
+	 */
+	private boolean checkSend(String phone) {
 		// 每分钟1条
 		String key = phone + "_limit_minute";
 		String result = RedisUtil.get(key);
@@ -58,20 +86,16 @@ public class SmsService {
 		if(Objects.nonNull(result)) {
 			int count = Integer.parseInt(result);
 			if(count >= 10) {
-				logger.warn("每小时限制5条: {}", phone);
+				logger.warn("每天限制10条: {}", phone);
 				return false;
 			}
 			RedisUtil.set(key, count, 1, TimeUnit.DAYS);
 		}else {
 			RedisUtil.set(key, 1, 1, TimeUnit.DAYS);
 		}
-		// 发送短信
-		String code = String.valueOf(RandomUtil.getRandomInt(4));
-		RedisUtil.set(phone + "_" + code, "", 10, TimeUnit.MINUTES); // 有效期10分钟
-		aliyunService.sendCode(phone, code); // 第三方发送短信
 		return true;
 	}
-	
+
 	/**
 	 * 检查验证码
 	 * @param phone

+ 52 - 1
src/main/java/com/llisoft/service/sms/vo/SendCodeRequestVo.java

@@ -1,6 +1,7 @@
 package com.llisoft.service.sms.vo;
 
 import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Pattern;
 
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
@@ -10,14 +11,64 @@ public class SendCodeRequestVo {
 	
 	@ApiModelProperty("手机号码")
 	@NotBlank(message="手机号码不能为空")
+	@Pattern(regexp="1[0-9]{10}")
 	private String phone;
+	
+	@ApiModelProperty("验证码参数:appkey")
+	@NotBlank(message="验证码参数:appkey不能为空")
+	private String appkey;
+	
+	@ApiModelProperty("验证码参数:scene")
+	@NotBlank(message="验证码参数:scene不能为空")
+	private String scene;
+	
+	@ApiModelProperty("验证码参数:token")
+	@NotBlank(message="验证码参数:token不能为空")
+	private String token;
+	
+	@ApiModelProperty("验证码参数:sessionid")
+	@NotBlank(message="验证码参数:sessionid不能为空")
+	private String sessionid;
+	
+	@ApiModelProperty("验证码参数:sid")
+	@NotBlank(message="验证码参数:sid不能为空")
+	private String sid;
 
 	public String getPhone() {
 		return phone;
 	}
-
 	public void setPhone(String phone) {
 		this.phone = phone;
 	}
+	public String getAppkey() {
+		return appkey;
+	}
+	public void setAppkey(String appkey) {
+		this.appkey = appkey;
+	}
+	public String getScene() {
+		return scene;
+	}
+	public void setScene(String scene) {
+		this.scene = scene;
+	}
+	public String getSid() {
+		return sid;
+	}
+	public void setSid(String sid) {
+		this.sid = sid;
+	}
+	public String getToken() {
+		return token;
+	}
+	public void setToken(String token) {
+		this.token = token;
+	}
+	public String getSessionid() {
+		return sessionid;
+	}
+	public void setSessionid(String sessionid) {
+		this.sessionid = sessionid;
+	}
 
 }

+ 33 - 0
src/main/java/com/llisoft/service/sms/vo/SendMsgRequestVo.java

@@ -0,0 +1,33 @@
+package com.llisoft.service.sms.vo;
+
+import javax.validation.constraints.NotBlank;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+@ApiModel("发送消息请求实体")
+public class SendMsgRequestVo {
+	
+	@ApiModelProperty("手机号码")
+	@NotBlank(message="手机号码不能为空")
+	private String phone;
+	
+	private String msg;
+
+	public String getPhone() {
+		return phone;
+	}
+
+	public void setPhone(String phone) {
+		this.phone = phone;
+	}
+
+	public String getMsg() {
+		return msg;
+	}
+
+	public void setMsg(String msg) {
+		this.msg = msg;
+	}
+
+}

+ 1 - 2
src/test/java/com/llisoft/service/sms/ServiceTest.java

@@ -18,8 +18,7 @@ public class ServiceTest {
 	@Test
 	public void test() throws Exception{
 		long begin = System.currentTimeMillis();
-		System.out.println(smsService.sendCode("13552635233"));
-//		System.out.println(smsService.checkCode("13552635233", "5507"));
+		System.out.println(smsService.checkCode("13552635233", "5507"));
 		System.out.println("耗时:"+ (System.currentTimeMillis() - begin));
 	}