这个系列主要针对对Redis的系统学习,会逐步利用redis来做一些缓存实战
有关当前模型
手机或者app端发起请求,请求我们的nginx服务器,nginx基于七层模型走的是HTTP协议,可以实现基于Lua直接绕开tomcat访问redis,也可以作为静态资源服务器,轻松扛下上万并发, 负载均衡到下游tomcat服务器,打散流量,我们都知道一台4核8G的tomcat,在优化和处理简单业务的加持下,大不了就处理1000左右的并发, 经过nginx的负载均衡分流后,利用集群支撑起整个项目,同时nginx在部署了前端项目后,更是可以做到动静分离,进一步降低tomcat服务的压力,这些功能都得靠nginx起作用,所以nginx是整个项目中重要的一环。
在tomcat支撑起并发流量后,我们如果让tomcat直接去访问Mysql,根据经验Mysql企业级服务器只要上点并发,一般是16或32 核心cpu,32 或64G内存,像企业级mysql加上固态硬盘能够支撑的并发,大概就是4000起~7000左右,上万并发, 瞬间就会让Mysql服务器的cpu,硬盘全部打满,容易崩溃,所以我们在高并发场景下,会选择使用mysql集群,同时为了进一步降低Mysql的压力,同时增加访问的性能,我们也会加入Redis,同时使用Redis集群使得Redis对外提供更好的服务。
对于短信登录实现方法有多种,例如session,jwt
使用Session和使用JWT(JSON Web Token)实现用户认证和授权的方式有一些区别,先说一下它们之间的主要区别:
-
存储方式:
-
Session:Session存储在服务器端,通常存储在内存或数据库中。服务器会为每个会话分配一个唯一的Session ID,并将Session ID存储在客户端的Cookie中。
-
JWT:JWT是一种基于JSON的令牌,包含用户信息和签名。JWT生成后可以存储在客户端的LocalStorage或SessionStorage中,服务器无需保存任何状态信息。
-
-
状态管理:
-
Session:需要在服务器端维护Session状态,包括Session ID、用户信息等。服务器需要消耗一定的资源来管理Session状态。
-
JWT:无状态,服务器端不需要维护任何状态信息,所有信息都包含在JWT中。这样可以减轻服务器的负担,提高可伸缩性。
-
-
安全性:
-
Session:Session基于服务器端存储,相对安全。但可能存在会话劫持、跨站点请求伪造(CSRF)等安全风险。
-
JWT:JWT包含签名和加密信息,可以确保数据的完整性和安全性。但如果JWT泄露,攻击者可以解码其中的信息。
-
-
扩展性:
-
Session:需要在服务器端维护Session状态,可能会影响系统的扩展性和性能。
-
JWT:无状态,可以轻松扩展到多个服务实例或跨域服务。
-
虽然JWT看起来更好一点,但是为了巩固一下各种实现方法,先将session的说一下
1.基于Session实现登录流程
基于session实现登录主要分为三个流程
-
发送短信验证码
-
短信验证码登录、注册
-
校验登录状态
具体流程看下方流程图:
2.实现发送短信验证码功能
既然我们要校验验证码,我们就需要知道如何生成验证码?如何保存验证码?如何发送验证码?
生成验证码:可以利用随机数生成
保存验证码:只需要将验证码保存在session会话中就行
发送验证码:我们先用log日志模拟发送验证码,后期在相关业务中再选择对应的发送方式
代码如下:
-
发送验证码
@Override
public Result sendCode(String phone, HttpSession session) {
// 1.校验手机号
if (RegexUtils.isPhoneInvalid(phone)) {
// 2.如果不符合,返回错误信息
return Result.fail("手机号格式错误!");
}
// 3.符合,生成验证码
String code = RandomUtil.randomNumbers(6);
// 4.保存验证码到 session
session.setAttribute("code",code);
// 5.发送验证码
log.debug("发送短信验证码成功,验证码:{}", code);
// 返回ok
return Result.ok();
}
发送验证码之后就需要登录校验
具体逻辑:校验手机号是否合法->校验验证码是否一致->如果一致,验证码校验通过/如果不一致,报错->校验通过需要根据手机号去查询是否有该用户->如果不存在,创建一个user->将用户信息保存到session中
那么就引出了一个简单的问题,为什么要保存到session中?
原因是服务器会为每个会话分配一个唯一的Session ID,并将Session ID存储在客户端的Cookie中,可以理解为用户在登录的时候会在浏览器生成一个cookie,在这个cookie中存有session id,而每一个会话对应一个session id,该用户在不同页面进行操作的时候也可以保持用户信息,确保能够持续使用
代码如下:
-
登录
@Override
public Result login(LoginFormDTO loginForm, HttpSession session) {
// 1.校验手机号
String phone = loginForm.getPhone();
if (RegexUtils.isPhoneInvalid(phone)) {
// 2.如果不符合,返回错误信息
return Result.fail("手机号格式错误!");
}
// 3.校验验证码
Object cacheCode = session.getAttribute("code");
String code = loginForm.getCode();
if(cacheCode == null || !cacheCode.toString().equals(code)){
//3.不一致,报错
return Result.fail("验证码错误");
}
//一致,根据手机号查询用户
User user = query().eq("phone", phone).one();
//5.判断用户是否存在
if(user == null){
//不存在,则创建
user = createUserWithPhone(phone);
}
//7.保存用户信息到session中
session.setAttribute("user",user);
return Result.ok();
}