在自己学习慕课网瓦力老师的课程时,总结了基于springboot与阿里云实现免注册登录的实现。下面是整体的实现过程
简介
阿里云短信服务提供短信发送API接口SendSms和SendBatchSms,分别用于单个模板的短信单独或批量发送、多个短信模板的短信批量发送。短信服务(Short Message Service)是阿里云为用户提供的一种通信服务的能力。支持向国内和国际快速发送验证码、短信通知和推广短信
基于springboot
与阿里云实现免注册登录,类似常用网站的免注册登录,通过使用阿里云短信服务发送验证码,并在redis
中缓存验证码信息,过期清除,以实现通过手机号注册,接到验证码在一分钟内填写验证码,并跳转登录的功能。
这里只有后端的代码实现部分,前端页面等全部信息可以到github地址上面获取:
https://github.com/wqyuu/springboot-es
实战
项目基本环境以及配置:
https://blog.csdn.net/qq_37338761/article/details/102501961
pom.xml中添加依赖
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>3.2.3</version>
<!--<scope>system</scope>-->
<!--<systemPath>${project.basedir}/lib/aliyun-java-sdk-core-3.2.3.jar</systemPath>-->
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
<version>1.0.0</version>
<!--<scope>system</scope>-->
<!--<systemPath>${project.basedir}/lib/aliyun-java-sdk-dysmsapi-1.0.0.jar</systemPath>-->
</dependency>
项目中添加阿里云的lib
由于maven中没有aliyun的依赖,所以将lib放到根目录下面
配置文件增加redis配置、阿里云短信配置
redis直接配置本地的地址,我这里使用的是免密登录,开发环境可以这么做。
redis用来缓存短信的验证码,保留10分钟,过期删除
# redis config
spring.redis.database=0
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.pool.max-idle=8
spring.redis.timeout=3000
#session
spring.session.store-type=redis
# 阿里云短信配置 注意替换自己申请的配置
aliyun.sms.accessKey=LTAI4FeWmDfk8SErg2x6*****
aliyun.sms.accessKeySecret=MbpEfvvJ1qQgzKJHUUlLlX******
aliyun.sms.template.code=SMS_175533***
Controller
import com.wqy.springbootes.base.ApiResponse;
import com.wqy.springbootes.base.LoginUserUtil;
import com.wqy.springbootes.service.IUserService;
import com.wqy.springbootes.service.ServiceResult;
import org.apache.http.HttpStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class UserController {
@Autowired
private IUserService userService;
@GetMapping("/user/login")
public String loginPage(){
return "user/login";
}
@GetMapping("/user/center")
public String centerPage(){
return "user/center";
}
@GetMapping(value = "sms/code")
@ResponseBody
public ApiResponse smsCode(@RequestParam("telephone")String telephone){
if(!LoginUserUtil.checkTelephone(telephone)){
return ApiResponse.ofMessage(HttpStatus.BAD_REQUEST.value(),"请输入正确手机号");
}
ServiceResult<String> result = smsService.sendSms(telephone);
if(result.isSuccess()){
return ApiResponse.ofSuccess("");
}else{
return ApiResponse.ofMessage(HttpStatus.BAD_REQUEST.value(),result.getMessage());
}
}
}
ISmsService接口
/**
* 验证码服务
*/
public interface ISmsService {
/**
* 发送验证码到指定手机 并缓存验证码 10分钟 及 请求间隔时间1分钟
* @param telephone
* @return
*/
ServiceResult<String> sendSms(String telephone);
/**
* 获取缓存中的验证码
* @param telephone
* @return
*/
String getSmsCode(String telephone);
/**
* 移除指定手机号的验证码缓存
* @param telephone
*/
void remove(String telephone);
}
SmsServiceImpl 实现类
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.Random;
import java.util.concurrent.TimeUnit;
@Service
public class SmsServiceImpl implements ISmsService ,InitializingBean {
@Value("${aliyun.sms.accessKey}")
private String accessKey;
@Value("${aliyun.sms.accessKeySecret}")
private String secertKey;
@Value("${aliyun.sms.template.code}")
private String templateCode;
private IAcsClient acsClient;
@Autowired
private RedisTemplate<String, String> redisTemplate;
private final static String SMS_CODE_CONTENT_PREFIX="SMS::CODE::CONTENT";
private final static String NUMS[]={"0","1","2","3","4","5","6","7","8","9"};
private static final Random random = new Random();
@Override
public ServiceResult<String> sendSms(String telephone) {
String gapKey = "SMS::CODE::INTERVAL::"+telephone;
String result = redisTemplate.opsForValue().get(gapKey);
if(result!= null){ // 判断是否已缓存验证码
return new ServiceResult<String>(false,"请求次数太频繁");
}
String code =generateRandomSmsCode(); // 生成验证码
String templateParam = String.format("{\"code\":\"%s\"}",code);
//组装请求对象
SendSmsRequest request = new SendSmsRequest();
// 使用post提交
request.setMethod(MethodType.POST);
request.setPhoneNumbers(telephone);
request.setTemplateParam(templateParam);
request.setTemplateCode(templateCode);
request.setSignName("wqy-es");
boolean success = false;
try {
SendSmsResponse response = acsClient.getAcsResponse(request);
if("OK".equals(response.getCode())){
success = true;
}else{
//TODO log
}
} catch (ClientException e) {
e.printStackTrace();
}
if(success){
redisTemplate.opsForValue().set(gapKey,code,60,TimeUnit.SECONDS);
redisTemplate.opsForValue().set(SMS_CODE_CONTENT_PREFIX+telephone,code,10,TimeUnit.MINUTES);
return ServiceResult.of(code);
}else{
return new ServiceResult<String>(false,"系统忙,稍后重试");
}
}
@Override
public String getSmsCode(String telephone) {
return this.redisTemplate.opsForValue().get(SMS_CODE_CONTENT_PREFIX+telephone);
}
@Override
public void remove(String telephone) {
this.redisTemplate.delete(SMS_CODE_CONTENT_PREFIX+telephone);
}
@Override
public void afterPropertiesSet() throws Exception {
// 设置超时时间
System.setProperty("sun.net.client.defaultConnectTimeout","10000");
System.setProperty("sun.net.client.defaultReadTimeout","10000");
IClientProfile profile = DefaultProfile.getProfile("cn-beijing",accessKey,secertKey);
String product = "Dysmsapi";
String domain = "dysmsapi.aliyuncs.com";
DefaultProfile.addEndpoint("cn-beijing","cn-beijing",product,domain);
// 初始化短信客户端
this.acsClient = new DefaultAcsClient(profile);
}
private static String generateRandomSmsCode(){
StringBuilder sb = new StringBuilder();
for (int i = 0; i <6 ; i++) {
int index = random.nextInt(10);
sb.append(NUMS[index]);
}
return sb.toString();
}
}
结语
springboot可以很方便的整合各种常用框架,提升开发效率
免注册登录功能极大提升用户体验,虽然说需要后台帮助注册用户,这里要处理好登录之后,用户可以修改用户名的部分。
阿里云短信服务需要自己到阿里云官网申请,阿里云官网也包括JAVA API,使用示例,短信模板,短信签名。
参考
-
BAT大牛亲授基于ElasticSearch的搜房网实战 https://coding.imooc.com/class/167.html