AliSmsService.java 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. package com.izouma.nineth.service.sms;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.aliyuncs.CommonRequest;
  5. import com.aliyuncs.CommonResponse;
  6. import com.aliyuncs.DefaultAcsClient;
  7. import com.aliyuncs.IAcsClient;
  8. import com.aliyuncs.http.MethodType;
  9. import com.aliyuncs.profile.DefaultProfile;
  10. import com.izouma.nineth.config.Constants;
  11. import com.izouma.nineth.domain.SmsRecord;
  12. import com.izouma.nineth.exception.BusinessException;
  13. import com.izouma.nineth.repo.SmsRecordRepo;
  14. import io.jsonwebtoken.Jwts;
  15. import io.jsonwebtoken.SignatureAlgorithm;
  16. import lombok.extern.slf4j.Slf4j;
  17. import org.apache.commons.lang3.RandomStringUtils;
  18. import org.springframework.beans.factory.annotation.Autowired;
  19. import org.springframework.beans.factory.annotation.Value;
  20. import org.springframework.data.redis.core.RedisTemplate;
  21. import org.springframework.scheduling.annotation.Scheduled;
  22. import org.springframework.stereotype.Service;
  23. import java.time.Duration;
  24. import java.time.LocalDateTime;
  25. import java.time.ZoneOffset;
  26. import java.util.Date;
  27. import java.util.HashMap;
  28. @Service
  29. @Slf4j
  30. public class AliSmsService implements SmsService {
  31. @Value("${aliyun.access-key-id}")
  32. private String accessKeyId;
  33. @Value("${aliyun.access-key-secret}")
  34. private String accessKeySecret;
  35. @Value("${aliyun.sms-sign}")
  36. private String smsSign;
  37. @Value("${aliyun.sms-code}")
  38. private String smsCode;
  39. @Value("${aliyun.sell-out-code}")
  40. private String sellOutCode;
  41. @Value("${aliyun.saas-sell-out-code}")
  42. private String saasSellOutCode;
  43. @Autowired
  44. private SmsRecordRepo smsRecordRepo;
  45. @Autowired
  46. private RedisTemplate<String, Object> redisTemplate;
  47. @Override
  48. public String sendVerify(String phone) {
  49. if (smsSign.equals("身份验证")) {
  50. accessKeyId = "LTAI5tEL3wr9XeiyseqKLrEK";
  51. accessKeySecret = "I9JzOThjzeJMcpVf6melaMY3nt7ucU";
  52. }
  53. smsRecordRepo.findLastByPhoneAndExpiresAtAfterAndExpiredFalse(phone, LocalDateTime.now()).ifPresent(record -> {
  54. if (record.getCreatedAt().plusMinutes(1L).isAfter(LocalDateTime.now())) {
  55. long sec = record.getCreatedAt().plusMinutes(1L).toInstant(ZoneOffset.UTC)
  56. .getEpochSecond() - LocalDateTime.now().toInstant(ZoneOffset.UTC).getEpochSecond() + 1;
  57. throw new BusinessException("请" + sec + "秒后再试");
  58. }
  59. });
  60. String code = RandomStringUtils.randomNumeric(4);
  61. DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
  62. IAcsClient client = new DefaultAcsClient(profile);
  63. CommonRequest request = new CommonRequest();
  64. request.setMethod(MethodType.POST);
  65. request.setDomain("dysmsapi.aliyuncs.com");
  66. request.setVersion("2017-05-25");
  67. request.setAction("SendSms");
  68. request.putQueryParameter("PhoneNumbers", phone);
  69. request.putQueryParameter("SignName", smsSign);
  70. request.putQueryParameter("TemplateCode", smsCode);
  71. if (smsSign.equals("身份验证")) {
  72. request.putQueryParameter("TemplateParam", "{\"code\":\"" + code + "\",\"product\":\"用户\"}");
  73. } else {
  74. request.putQueryParameter("TemplateParam", "{\"code\":\"" + code + "\"}");
  75. }
  76. try {
  77. CommonResponse response = client.getCommonResponse(request);
  78. if (response.getHttpStatus() != 200) {
  79. throw new BusinessException("发送失败,请稍后再试", response.getHttpStatus() + "," + response.getData());
  80. }
  81. log.info("{} send sms response {}", phone, response.getData());
  82. JSONObject jsonObject = JSON.parseObject(response.getData());
  83. if (!"ok".equalsIgnoreCase(jsonObject.getString("Code"))) {
  84. throw new BusinessException("发送失败,请稍后再试", jsonObject.getString("Message"));
  85. }
  86. smsRecordRepo.expire(phone);
  87. String sessionId = RandomStringUtils.randomAlphabetic(10);
  88. smsRecordRepo.save(SmsRecord.builder()
  89. .sessionId(sessionId)
  90. .phone(phone)
  91. .code(code)
  92. .expiresAt(LocalDateTime.now().plusMinutes(5))
  93. .expired(false)
  94. .build());
  95. return sessionId;
  96. } catch (Exception e) {
  97. e.printStackTrace();
  98. throw new BusinessException("发送失败,请稍后再试", e.getMessage());
  99. }
  100. }
  101. @Override
  102. public String verify(String phone, String code) {
  103. if (Boolean.FALSE.equals(redisTemplate.opsForValue()
  104. .setIfAbsent("verify::" + phone, 1, Duration.ofSeconds(10)))) {
  105. throw new BusinessException("频繁操作,请稍后再试");
  106. }
  107. SmsRecord smsRecord = smsRecordRepo.findLastByPhoneAndExpiresAtAfterAndExpiredFalse(phone, LocalDateTime.now())
  108. .orElseThrow(new BusinessException("验证码错误"));
  109. if (!smsRecord.getCode().equalsIgnoreCase(code)) {
  110. throw new BusinessException("验证码错误");
  111. }
  112. smsRecord.setExpired(true);
  113. smsRecordRepo.save(smsRecord);
  114. return Jwts.builder()
  115. .setClaims(new HashMap<>())
  116. .setSubject(phone)
  117. .setIssuedAt(new Date())
  118. .setExpiration(new Date(new Date().getTime() + 10 * 60 * 1000)) //10min
  119. .signWith(SignatureAlgorithm.HS512, Constants.SMS_TOKEN_SECRET)
  120. .compact();
  121. }
  122. @Override
  123. public void sellOut(String phone, Long companyId) {
  124. if (companyId == null) companyId = 1L;
  125. DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
  126. IAcsClient client = new DefaultAcsClient(profile);
  127. CommonRequest request = new CommonRequest();
  128. request.setMethod(MethodType.POST);
  129. request.setDomain("dysmsapi.aliyuncs.com");
  130. request.setVersion("2017-05-25");
  131. request.setAction("SendSms");
  132. request.putQueryParameter("PhoneNumbers", phone);
  133. request.putQueryParameter("SignName", smsSign);
  134. request.putQueryParameter("TemplateCode", companyId == 1L ? sellOutCode : saasSellOutCode);
  135. if (companyId != 1L) {
  136. request.putQueryParameter("TemplateParam", "{\"url\":\"saas/" + companyId + "/home\"}");
  137. }
  138. try {
  139. CommonResponse response = client.getCommonResponse(request);
  140. if (response.getHttpStatus() != 200) {
  141. log.error("发送失败," + response.getHttpStatus() + "," + response.getData());
  142. }
  143. log.info("{} send sms response {}", phone, response.getData());
  144. JSONObject jsonObject = JSON.parseObject(response.getData());
  145. if (!"ok".equalsIgnoreCase(jsonObject.getString("Code"))) {
  146. log.error("发送失败," + jsonObject.getString("Message"));
  147. }
  148. } catch (Exception e) {
  149. e.printStackTrace();
  150. log.error("发送失败," + e.getMessage());
  151. }
  152. }
  153. @Scheduled(cron = "0 0 3 * * ?")
  154. void deleteExpired() {
  155. smsRecordRepo.deleteByCreatedAtBefore(LocalDateTime.now().minusDays(2));
  156. }
  157. }