springboot整合redis之发送手机验证码注册登录
2020-04-22 16:05:55来源:博客园 阅读 ()
springboot整合redis之发送手机验证码注册登录
springboot项目使用阿里云短信服务发送手机验证码-----(第二篇)
此文介绍:springboot整合redis之发送手机验证码注册登录
短信验证码是通过发送验证码到手机的一种有效的验证码系统。主要用于验证用户手机的合法性及敏感操作的身份验证。常见的使用场景有:登录注册、信息修改、异常登录、找回密码等操作。
用户注册发送验证码,然后核实对比用户注册成功采用redis方式将手机号码+key放入redis缓存中设置验证码超时时间,比对用户名和验证码采用数据库存储方式,注册时拿取redis中验证码进行判读验证码是否过期是否匹配。
注:搭建springboot项目可以参考这篇文章:https://www.cnblogs.com/bgyb/p/12070279.html
代码实现
pom.xml文件配置中添加以下依赖
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- 短信包--> <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-core</artifactId> <version>4.0.6</version> <!-- 注:如提示报错,先升级基础包版,无法解决可联系技术支持 --> </dependency> <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-dysmsapi</artifactId> <version>1.1.0</version> </dependency> <!--redis依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> </dependencies>
application.yml添加如下配置
# 服务端口 server: port: 8080 spring: #reids配置 redis: key: prefix: authCode: "portal:authCode:" orderId: "portal:orderId:" expire: authCode: 60 # 验证码超期时间 host: 127.0.0.1 # Redis服务器地址 database: 1 # Redis数据库索引(默认为0) port: 6379 # Redis服务器连接端口 password: # Redis服务器连接密码(默认为空) jedis: pool: max-active: 8 # 连接池最大连接数(使用负值表示没有限制) max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制) max-idle: 8 # 连接池中的最大空闲连接 min-idle: 0 # 连接池中的最小空闲连接 timeout: 3000ms # 连接超时时间(毫秒)
生成短信随机验证码工具类
import java.util.Random; public class CodeUtil { //使用到Algerian字体,系统里没有的话需要安装字体,字体只显示大写,去掉了1,0,i,o几个容易混淆的字符 public static final String VERIFY_CODES = "1234567890"; /** * 使用系统默认字符源生成验证码 * @param verifySize 验证码长度 * @return */ public static String generateVerifyCode(int verifySize){ return generateVerifyCode(verifySize, VERIFY_CODES); } /** * 使用指定源生成验证码 * @param verifySize 验证码长度 * @param sources 验证码字符源 * @return */ public static String generateVerifyCode(int verifySize, String sources){ if(sources == null || sources.length() == 0){ sources = VERIFY_CODES; } int codesLen = sources.length(); Random rand = new Random(System.currentTimeMillis()); StringBuilder verifyCode = new StringBuilder(verifySize); for(int i = 0; i < verifySize; i++){ verifyCode.append(sources.charAt(rand.nextInt(codesLen-1))); } return verifyCode.toString(); } public static void main(String[] args) { System.out.println(generateVerifyCode(4)); } }
短信下发工具类
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.profile.DefaultProfile; import com.aliyuncs.profile.IClientProfile; public class SmsTool { //产品名称:云通信短信API产品,开发者无需替换 static final String product = "Dysmsapi"; //产品域名,开发者无需替换 static final String domain = "dysmsapi.aliyuncs.com"; // TODO 此处需要替换成开发者自己的AK(在阿里云访问控制台寻找) static final String accessKeyId = "自己的AccessKeyId"; static final String accessKeySecret = "自己的accesskeySecret"; public static SendSmsResponse sendSms(String phone , String code) throws ClientException { //可自助调整超时时间 System.setProperty("sun.net.client.defaultConnectTimeout", "10000"); System.setProperty("sun.net.client.defaultReadTimeout", "10000"); //初始化acsClient,暂不支持region化 IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret); DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain); IAcsClient acsClient = new DefaultAcsClient(profile); //组装请求对象-具体描述见控制台-文档部分内容 SendSmsRequest request = new SendSmsRequest(); //必填:待发送手机号 request.setPhoneNumbers(phone); //必填:短信签名-可在短信控制台中找到 request.setSignName("替换成自己的短信签名"); //必填:短信模板-可在短信控制台中找到 request.setTemplateCode("替换成自己的短信模板编号"); //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为 request.setTemplateParam(code); //选填-上行短信扩展码(无特殊需求用户请忽略此字段) //request.setSmsUpExtendCode("90997"); //可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者 //request.setOutId("yourOutId"); //hint 此处可能会抛出异常,注意catch SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request); return sendSmsResponse; } }
reids工具类接口
public interface RedisService { /** * 存储数据 */ void set(String key, String value); /** * 获取数据 */ String get(String key); /** * 设置超期时间 */ boolean expire(String key, long expire); /** * 删除数据 */ void remove(String key); /** * 自增操作 * @param delta 自增步长 */ Long increment(String key, long delta); }
reids实现类
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import java.util.concurrent.TimeUnit; @Service public class RedisServiceImpl implements RedisService{ @Autowired private StringRedisTemplate stringRedisTemplate; @Override public void set(String key, String value) { stringRedisTemplate.opsForValue().set(key, value); } @Override public String get(String key) { return stringRedisTemplate.opsForValue().get(key); } @Override public boolean expire(String key, long expire) { return stringRedisTemplate.expire(key, expire, TimeUnit.SECONDS); } @Override public void remove(String key) { stringRedisTemplate.delete(key); } @Override public Long increment(String key, long delta) { return stringRedisTemplate.opsForValue().increment(key,delta); } }
Controller拦截类
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; import com.aliyuncs.exceptions.ClientException; import com.aliyuncs.utils.StringUtils; import or.og.smsdemo.redisutil.RedisService; import or.og.smsdemo.util.CodeUtil; import or.og.smsdemo.util.SmsTool; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Map; @Controller @RequestMapping("/sms") public class SmsCtrlController { /*** * 注入redis模版 */ @Autowired private RedisService redisService; private String tokenId="TOKEN-USER-"; /** * 发送短信 * @ResponseBody 返回json数据 * @RequestMapping 拦截请求,指定请求类型:POST * @RequestBody 接受前台传入的json数据 接受类型为Map * @throws ClientException 抛出异常 */ @ResponseBody @RequestMapping(value = "/smsXxs", method = RequestMethod.POST, headers = "Accept=application/json") public Map<String,Object> smsXxs(@RequestBody Map<String,Object> requestMap,HttpServletRequest request) throws ClientException { Map<String,Object> map = new HashMap<>(); String phone = requestMap.get("phoneNumber").toString(); // 调用工具栏中生成验证码方法(指定长度的随机数) String code = CodeUtil.generateVerifyCode(6); //填充验证码 String TemplateParam = "{\"code\":\""+code+"\"}"; SendSmsResponse response = SmsTool.sendSms(phone,TemplateParam);//传入手机号码及短信模板中的验证码占位符 map.put("verifyCode",code); map.put("phone",phone); request.getSession().setAttribute("CodePhone",map); if( response.getCode().equals("OK")) { map.put("isOk","OK"); //验证码绑定手机号并存储到redis redisService.set(tokenId+phone,code); redisService.expire(tokenId+phone,620);//调用reids工具类中存储方法设置超时时间 } return map; } /** * 注册验证 * @ResponseBody 返回json数据 * @RequestMapping 拦截请求,指定请求类型:POST * @RequestBody 接受前台传入的json数据 接受类型为Map * @throws ClientException 抛出异常 */ @ResponseBody @RequestMapping(value = "/validateNum", method = RequestMethod.POST, headers = "Accept=application/json") public Map<String, Object> validateNum(@RequestBody Map<String,Object> requestMap) throws ClientException { Map<String,Object> map = new HashMap<>(); String phone = requestMap.get("phone").toString();//获取注册手机号码 String verifyCode = requestMap.get("verifyCode").toString();//获取手机验证码 //首先比对验证码是否失效 String redisauthcode= redisService.get(tokenId+phone); //传入tonkenId返回redis中的value if(StringUtils.isEmpty(redisauthcode)){ //如果未取到则过期验证码已失效 map.put("ruselt",404); }else if(!"".equals(redisauthcode)&&!verifyCode.equals(redisauthcode)){ //验证码错误 map.put("ruselt",500); }else{ //用户注册成功 map.put("ruselt",200); } return map; } }
静态页面index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>springboot整合redis之用户手机验证码注册登录</title> <script type="text/javascript" src="js/jquery-1.9.1.js"></script> </head> <body> <!-- <h3>springboot整合redis之用户手机验证码注册登录</h3>--> <div class="form-group has-feedback"> <input type="tel" class="form-control" id="phone" placeholder="请输入手机号" maxlength=11> <span class="glyphicon glyphicon-earphone form-control-feedback"></span> </div> <div class="row"> <div class="col-xs-6 pull_left"> <div class="form-group"> <input class="form-control" id="msg_num" placeholder="请输入验证码"> </div> </div> <div class="col-xs-6 pull_center"> <div class="form-group"> <input type="button" class="btn btn-block btn-flat" id="verify_refresh" onclick="getMsgNum(this)" value="免费获取验证码"> </div> </div> </div> <div class="col-xs-12 pull_center"> <button type="button" class="btn btn-block btn-flat" onclick="validateNum()">验证</button> </div> <!--js中的代码--> <script> var messageData; var wait = 120; // 短信验证码120秒后才可获取下一个 /** * 获取验证码 */ function getMsgNum(that) { var phoneNumber = $('#phone').val(); setButtonStatus(that); // 设置按钮倒计时 var obj = { phoneNumber: phoneNumber }; $.ajax({ url: 'sms/smsXxs', // 后台短信发送接口 type: 'POST', dataType: 'json', contentType: "application/json", async: false, //false 同步 data: JSON.stringify(obj), xhrFields: { //为true实现跨域访问 withCredentials: true }, success: function (result) { if(result.isOk="OK") { alert("验证码发送成功"); messageData = result; }else { alert("验证码发送失败") } }, error: function (XMLHttpRequest, textStatus, errorThrown) { console.log(XMLHttpRequest.status); console.log(XMLHttpRequest.readyState); console.log(textStatus); } }); } /** * 设置按钮状态 */ function setButtonStatus(that) { if (wait == 0) { that.removeAttribute("disabled"); that.value="免费获取验证码"; wait = 60; } else { that.setAttribute("disabled", true); that.value=wait+"秒后可以重新发送"; wait--; setTimeout(function() { setButtonStatus(that) }, 1000) } } /** * 注册按钮 */ function validateNum() { var data = { // verifyCode: messageData.verifyCode, // phone: messageData.phone, verifyCode: $('#msg_num').val(), phone: $('#phone').val(), }; $.ajax({ url: 'sms/validateNum', // 后台短信发送接口 type: 'POST', dataType: 'json', contentType: "application/json", async: false, //false 同步 data: JSON.stringify(data), xhrFields: { //为true实现跨域访问 withCredentials: true }, success: function (result) { if(result.ruselt=="404") { alert("过期验证码已失效"); }else if(result.ruselt=="500"){ alert("验证码错误") }else{ alert("验证成功"); } }, error: function (XMLHttpRequest, textStatus, errorThrown) { console.log(XMLHttpRequest.status); console.log(XMLHttpRequest.readyState); console.log(textStatus); } }); } </script> </body> </html>
完成以上代码就可以运行项目了打开浏览器输入http://localhost:8080/,就可访问index.html文件,效果如下。。。。
输入手机号码点击获取验证码:
随后我们去的redis中查看是否将验证码保存到redis中,此时我们看见redis已经完成了缓存的实现并且设置了缓存超时时间。
输入上手机短信验证码传入进行一系列处理,后台获取前台传入的验证码同时获取redis缓存中的验证码进行匹配该验证码是否有效、是否过期等问题验证!
个人总结:
在此个人只是做了一个小例子,各大网友可自行扩展功能业务,学习是永无止境的!
原文链接:https://www.cnblogs.com/bgyb/p/12743859.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- redis缓存 2020-06-12
- springboot2配置JavaMelody与springMVC配置JavaMelody 2020-06-11
- SpringBoot 2.3 整合最新版 ShardingJdbc + Druid + MyBatis 2020-06-11
- 掌握SpringBoot-2.3的容器探针:实战篇 2020-06-11
- Spring Boot 2.3.0 新特性Redis 拓扑动态感应 2020-06-11
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash