篮球小凯 level
获赞
27
粉丝
5
关注
26
看过 TA
347
河北工程大学
2028
Java
IP属地:辽宁
暂未填写个人简介
私信
关注
01-12 01:19
已编辑
河北工程大学 Java
借鉴了一个博主的,我把完整代码实现,测试没问题下面考虑一个问题,用户请求发送验证码时,服务器这边的逻辑是直接调用相关接口(这里需要运营商提供增值服务),将验证码发给用户,同时服务器端也会存储一份验证码。但是如果有人恶意使用这项功能,大量发送无效验证码,那么就会给服务器带来压力,同时增加公司的开销,这正是我们愿意看到的(bushi)。所以这里需要对请求中的手机号获取验证码进行次数限制。在我们的日常使用中,一般一分钟只能获取一次验证码,这里的实现思路很简单,可以称为使用锁的思想,每次有请求想要获取验证码时先检查redis中是否存在对应的锁,如果存在,则返回失败,如果不存在,则生成验证码并在redis中设置一个过期时间为一分钟的锁。同时还可以实现一个黑名单功能,限制一个手机号一小时内只能获取3次验证码,超过次数则拉入黑名单,24小时后从黑名单中移除。public class RedisConstants {// 1分钟限频Key前缀(格式:verify:limit:手机号)public static final String VERIFY_LIMIT_KEY = "verify:limit:";// 1分钟限频过期时间(单位:秒)public static final Long VERIFY_LIMIT_TTL = 60L;// 请求次数统计Key前缀(格式:verify:count:手机号)public static final String VERIFY_COUNT_KEY = "verify:count:";// 次数统计过期时间(比如1小时,避免长期占用内存)public static final Long VERIFY_COUNT_TTL = 3600L;// 黑名单Key前缀(格式:verify:black:手机号)public static final String VERIFY_BLACK_KEY = "verify:black:";// 黑名单过期时间(24小时,单位:秒)public static final Long VERIFY_BLACK_TTL = 86400L;}@Overridepublic Result sendCode(String phone, HttpSession session) {//1,校验手机号if (RegexUtils.isPhoneInvalid(phone)) {//2,不符合,返回错误信息return Result.fail("手机格式错误!");}String blackKey = RedisConstants.VERIFY_BLACK_KEY + phone;if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(blackKey))) {// 已在黑名单,拒绝请求return Result.fail("已在黑名单,拒绝请求,24小时之后再访问,亲!");}// 步骤2:判断是否触发“1分钟限1次”String limitKey = RedisConstants.VERIFY_LIMIT_KEY + phone;if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(limitKey))) {// 1分钟内已请求过,拒绝return Result.fail("1分钟内访问过一次");}// 步骤3:统计请求次数,判断是否超3次String countKey = RedisConstants.VERIFY_COUNT_KEY + phone;// 自增请求次数(初始为1)Long count = stringRedisTemplate.opsForValue().increment(countKey);// 设置过期时间(仅第一次自增时设置)if (count == 1) {stringRedisTemplate.expire(countKey, RedisConstants.VERIFY_COUNT_TTL, TimeUnit.SECONDS);}// 步骤4:次数超3次 → 加入黑名单if (count > 2) { //调试的这里是2,因为这个逻辑在验证的后面stringRedisTemplate.opsForValue().set(blackKey, "1", RedisConstants.VERIFY_BLACK_TTL, TimeUnit.SECONDS);// 清除次数统计和限频Key(可选,避免干扰)stringRedisTemplate.delete(countKey);stringRedisTemplate.delete(limitKey);}// 步骤5:通过所有校验 → 设置1分钟限频锁stringRedisTemplate.opsForValue().set(limitKey, "1", RedisConstants.VERIFY_LIMIT_TTL, TimeUnit.SECONDS);// 后续逻辑:生成验证码、调用运营商接口发送等//3,符合,生成验证码String code = RandomUtil.randomNumbers(6);//4保存验证码到redis 有效期stringRedisTemplate.opsForValue().set("login:code"+phone,code,2, TimeUnit.MINUTES);//5,发送验证码log.debug("发送短信验证码成功,验证码:{}",code);//返回okreturn Result.ok();}
0 点赞 评论 收藏
分享
2025-12-27 20:35
河北工程大学 Java
其实从cookie到token演变经历了这10多年的互联网发展。三者在作用上是一致的,都是为了标识用户,区别在于对于安全性的要求及探索。cookie很简单,就是用户登录后,服务器生成一串字符返回给客户浏览器,存储下来。下次访问该网站,浏览器自动携带该字符串,以便标识该用户,省去输入账号和密码的麻烦。其实早期就是为了方便,并没有考虑安全,早期网页很简单,没什么敏感数据。这时的cookie字符串很多都是账号与密码的简单组合。随着大家注意到安全问题,大家就着手对cookie做些变化,从简单变化到使用哈希算法加密,逐渐演变成了session。无论cookie还是session其实都没有真正解决安全问题,session像是掩耳盗铃,虽然对cookie各种变化包装,但只要session泄漏,别人轻而易举就可以访问该用户数据。这时已经有很多公司考虑一种更加安全的机制。由于移动互联的发展,手机应用不像浏览器自带cookie,这推动了一种更加安全的方案token。session之于cookie区别在于那串字符的加密。token区别除了加密更侧重的则是客户端与服务端的鉴权,结合对称与非对称加密,使用时间戳等等。比较完善的加密鉴权方案还是挺复杂的,而且每个公司,每个产品的方案可能都有所区别。cookie可以说是已经淘汰的东西了,现在公司一般都会采用token方案。实际开发也不用想的太复杂,各种库一般都封装了基本的功能,调用接口根据需求相应调整即可。大些的公司可能会结合jwt设计一套自己的方案。总之作为开发者要知道:技术不是绝对的,技术是在不断变化发展的。
0 点赞 评论 收藏
分享

创作者周榜

更多
关注他的用户也关注了:
牛客网
牛客网在线编程
牛客网题解
牛客企业服务