阿里云短信验证解决方案(java版)(redis存储)
最近搞了一个互联网项目的注册,需要写一个手机号验证(由于之前没有轮子,只能自己摸索了);
1:基本思路:
1>购买了阿里云短信服务->下载阿里云短信发送demo(java版);
2>后端随机产生二维码,通过阿里云短信服务${code}进行发送
3>同时记录发送的code和客户端的手机号,存储在redis中,redis过期时间60秒;
4>用户注册提交将客户端手机号和验证码与redis中的key和value对比,存在则注册成功(同时删除redis对应缓存数据),不存在则返回;
如需询问 可加我QQ820688215
========================================================================================================
代码如下:
redis工具代码
maven:
<!--阿里云短信服务-->
<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>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
redis 服务类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | public class RedisClientServer { private static final Logger logger = LoggerFactory.getLogger(RedisClientServer. class ); private static JedisPool jedisPool = null ; private static Jedis jedis = null ; public static Jedis jedis_object = null ; private static String host = "127.0.0.1" ; private static String password = "123456" ; private static Integer port = 6379 ; static { if (jedisPool == null ){ JedisPoolConfig config = new JedisPoolConfig(); //设置最大连接数 config.setMaxTotal( 500 ); //设置最大空闲数 config.setMaxIdle( 20 ); //设置最小空闲数 config.setMinIdle( 8 ); //设置超时时间 config.setMaxWaitMillis( 3000 ); //Idle时进行连接扫描 config.setTestWhileIdle( true ); //表示idle object evitor两次扫描之间要sleep的毫秒数 config.setTimeBetweenEvictionRunsMillis( 30000 ); //表示idle object evitor每次扫描的最多的对象数 config.setNumTestsPerEvictionRun( 10 ); //表示一个对象至少停留在idle状态的最短时间,然后才能被idle object evitor //扫描并驱逐;这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义 config.setMinEvictableIdleTimeMillis( 60000 ); //初始化连接池 jedisPool = new JedisPool(config, host, port); jedis_object = new Jedis( host, port); } } private RedisClientServer() { } private static Jedis getJedisInstance(){ try { if ( null == jedis){ jedis = jedisPool.getResource(); jedis.auth(password); } } catch (Exception e) { logger.error( "实例化jedis失败........." , e); } return jedis; } /** * 向缓存中设置字符串内容 *@author liudianpeng.com *@date */ public static boolean set(String key, String value) throws Exception { Jedis jedis = null ; try { jedis = getJedisInstance(); jedis.set(key, value); return true ; } catch (Exception e) { logger.error( "redis set方法失败...key=" +key+ " value=" +value, e); } finally { jedisPool.close(); } return false ; } /** * 向缓存中设置字符串内容 ,设置过期时间 *@author liudianpeng.com *@date */ public static boolean set(String key, String value,Integer seconds) throws Exception { Jedis jedis = null ; try { jedis = getJedisInstance(); jedis.set(key, value); jedis.expire(key, seconds); return true ; } catch (Exception e) { logger.error( "redis set方法失败...key=" +key+ " value=" +value, e); } finally { jedisPool.close(); } return false ; } /** * 根据key 获取内容 *@author liudianpeng.com *@date */ public static Object get(String key) { Jedis jedis = null ; try { jedis = getJedisInstance(); Object value = jedis.get(key); return value; } catch (Exception e) { logger.error( "redis get方法失败...key=" +key); } finally { jedisPool.close(); } return null ; } /** * 删除缓存中得对象,根据key *@author liudianpeng.com *@date */ public static boolean del(String key) { Jedis jedis = null ; try { jedis = getJedisInstance(); jedis.del(key); return true ; } catch (Exception e) { e.printStackTrace(); } finally { jedisPool.close(); } return false ; } /** * 根据key 获取对象 *@author liudianpeng.com *@date */ public static <T> T get(String key, Class<T> clazz) { Jedis jedis = null ; try { jedis = getJedisInstance(); String value = jedis.get(key); return JSON.parseObject(value, clazz); } catch (Exception e) { e.printStackTrace(); } finally { jedisPool.close(); } return null ; } /** * 设置key过期 *@author *@date */ public static boolean expire(String key, int seconds){ Jedis jedis = null ; try { jedis = getJedisInstance(); jedis.expire(key, seconds); return true ; } catch (Exception e) { e.printStackTrace(); } finally { jedisPool.close(); } return false ; } /** * 判断是否存在key *@author *@date */ public static Boolean exists(String key){ Jedis jedis = null ; try { jedis = getJedisInstance(); return jedis.exists(key); } catch (Exception e) { e.printStackTrace(); return false ; } finally { jedisPool.close(); } } } |
随机code生成工具
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | public class CoreUtils { /** * 生成随机字符串 * * @param length * @return */ public static String randomString( int length, boolean isNumeric) { String base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" ; if (isNumeric) { base = "0123456789" ; } Random random = new Random(); StringBuffer buffer = new StringBuffer(length); for ( int i = 0 ; i < length; i++) { buffer.append(base.charAt(random.nextInt(base.length()))); } return buffer.toString(); } /** * 不重复的参数进行拼装,返回查询条件字符串 * * @param parameters 参数map * @param sort 是否按照字典排序 * @return */ public static String generateQueryString(Map<String, Object> parameters, boolean sort) { ArrayList<String> list = new ArrayList<String>(); for (Map.Entry<String, Object> entry : parameters.entrySet()) { // log.debug("参数:{}", entry.getKey()); if (! "" .equals(entry.getValue())) { list.add(entry.getKey() + "=" + entry.getValue()); } } String[] arrayToSort = list.toArray( new String[list.size()]); if (sort) { Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER); } StringBuffer buffer = new StringBuffer(); for ( int i = 0 ; i < list.size(); i++) { buffer.append(arrayToSort[i]); if (i < (list.size() - 1 )) { buffer.append( "&" ); } } return buffer.toString(); } /** * 根据参数获得相关签名 * * @param buffer 加密参数,ASCII 码从小到大排序(字典序) * @param encrypt 加密方式 SHA1 MD5 * @return */ public static String signature(String buffer, String encrypt, boolean toUpperCase) { String sign = "" ; if ( "MD5" .equals(encrypt)) { // MD5加密 sign = Hashing.md5().hashString(buffer, Charsets.UTF_8).toString(); } else if ( "SHA1" .equals(encrypt)) { // SHA1加密 sign = Hashing.sha1().hashString(buffer, Charsets.UTF_8).toString(); } if (toUpperCase) { sign = sign.toUpperCase(); } return sign; } /** * 根据参数获得相关签名 * * @param params 加密参数,ASCII 码从小到大排序(字典序) * @param encrypt 加密方式 SHA1 MD5 * @return */ public static String signature(Map params, String encrypt, boolean toUpperCase) { String sign = "" ; // 拼接字符串,按照字典排序 String buffer = generateQueryString(params, true ); // log.debug("待加密的字符串 => {}", buffer.toString()); if ( "MD5" .equals(encrypt)) { // MD5加密 sign = Hashing.md5().hashString(buffer, Charsets.UTF_8).toString(); } else if ( "SHA1" .equals(encrypt)) { // SHA1加密 sign = Hashing.sha1().hashString(buffer, Charsets.UTF_8).toString(); } // log.debug("加密后的字符串 <=> {}", sign); if (toUpperCase) { sign = sign.toUpperCase(); } return sign; } } |
阿里云短信服务配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | /** * SmsDemo 是官方demo * 对其进行了修改, * 1:sendMsg 发送短信消息给客户端,需要客户端传入手机号 */ public class MessageUtils { /** * 发送短信消息方法,返回验证码 * @param phone 用户手机号 * @return true 发送成功 ;false 发送失败 */ public static Boolean sendMsg(String phone) throws Exception { //设置超时时间-可自行调整 System.setProperty( "sun.net.client.defaultConnectTimeout" , "10000" ); System.setProperty( "sun.net.client.defaultReadTimeout" , "10000" ); //初始化ascClient需要的几个参数 final String product = "Dysmsapi" ; //短信API产品名称(短信产品名固定,无需修改) final String domain = "dysmsapi.aliyuncs.com" ; //短信API产品域名(接口地址固定,无需修改) //替换成你的AK final String accessKeyId = "" ; //你的accessKeyId,参考本文档步骤2 final String accessKeySecret = "" ; //你的accessKeySecret,参考本文档步骤2 //初始化ascClient,暂时不支持多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(); //使用post提交 request.setMethod(MethodType.POST); //必填:待发送手机号。支持以逗号分隔的形式进行批量调用,批量上限为1000个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式 request.setPhoneNumbers(phone); //必填:短信签名-可在短信控制台中找到 request.setSignName( "你的短信签名" ); //必填:短信模板-可在短信控制台中找到 request.setTemplateCode( "SMS_0930219321" ); String checkCode = CoreUtils.randomString( 6 , true ); //此处是生成6位数验证码工具类 //request.setTemplateParam("{\"code\":\"123\"}");//测试用,此处json一定要严格按照json格式书写 request.setTemplateParam( "{\"code\":\"" +checkCode+ "\"}" ); //可选-上行短信扩展码(扩展码字段控制在7位或以下,无特殊需求用户请忽略此字段) //request.setSmsUpExtendCode("90997"); //可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者 request.setOutId( "yourOutId" ); //请求失败这里会抛ClientException异常 SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request); if (sendSmsResponse.getCode() != null && sendSmsResponse.getCode().equals( "OK" )){ //请求成功,短信已发送 //将手机号和生成的随机数存入redis 并设置redis的过期时间 RedisClientServer.set(phone,checkCode, 60 ); } return sendSmsResponse.getCode() != null && sendSmsResponse.getCode().equals( "OK" ); } //测试发送短信 public static void main (String[] args) throws Exception { Boolean s = MessageUtils.sendMsg( "13279879821" ); //手机号 System.out.println( "==========" +s); } |
//客户端请求处理
1 2 3 4 5 6 7 8 | //获取redis缓存中的手机号(key)和验证码(value)://///////////////////////// if ( "" .equals((RedisClientServer.get(dto.getMobile())).toString())|| null ==(RedisClientServer.get(dto.getMobile())).toString()){ return Results.json().render( "验证码已过期" ); } else { //删除缓存数据 RedisClientServer.del(dto.getMobile()); } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了