likes
comments
collection
share

搞懂Session就是现在!

作者站长头像
站长
· 阅读数 30

小序

第二篇文章是前后端的交互出发,讲述了服务间的通信:

而本篇文章将会告诉您:

  1. session到底是个啥?
  2. session 与 jwt的区别?

正文

Session

以登录功能为例(详细可以看第一篇文章,文章中有git地址,是一个最简单的企业级项目——用户管理系统)

当然,并不会影响您阅读本篇文章的体验!

controller层

@PostMapping("/login")
public BaseResponse<User> userLogin(@RequestBody UserLoginRequest userLoginRequest, HttpServletRequest request) {
if (userLoginRequest == null) {
    return ResultUtils.error(ErrorCode.PARAMS_ERROR);
}
String userAccount = userLoginRequest.getUserAccount();
String userPassword = userLoginRequest.getUserPassword();
if (StringUtils.isAnyBlank(userAccount, userPassword)) {
    return ResultUtils.error(ErrorCode.PARAMS_ERROR);
}
User user = userService.userLogin(userAccount, userPassword, request);
return ResultUtils.success(user);
}

service接口

/**
 * 用户登录
 *
 * @param userAccount  用户账户
 * @param userPassword 用户密码
 * @param request
 * @return 脱敏后的用户信息
 */
User userLogin(String userAccount, String userPassword, HttpServletRequest request);

service实现层

@Override
public User userLogin(String userAccount, String userPassword, HttpServletRequest request) {
    // 1. 校验
    if (StringUtils.isAnyBlank(userAccount, userPassword)) {
        return null;
    }
    if (userAccount.length() < 4) {
        return null;
    }
    if (userPassword.length() < 8) {
        return null;
    }
    // 账户不能包含特殊字符
    String validPattern = "[`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?]";
    Matcher matcher = Pattern.compile(validPattern).matcher(userAccount);
    if (matcher.find()) {
        return null;
    }
    // 2. 加密
    String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());
    // 查询用户是否存在
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("userAccount", userAccount);
    queryWrapper.eq("userPassword", encryptPassword);
    User user = userMapper.selectOne(queryWrapper);
    // 用户不存在
    if (user == null) {
        log.info("user login failed, userAccount cannot match userPassword");
        return null;
    }
    // 3. 用户脱敏
    User safetyUser = getSafetyUser(user);
    // 4. 记录用户的登录态
    request.getSession().setAttribute(USER_LOGIN_STATE, safetyUser);
    return safetyUser;
}

最重要的也就是这句话:

request.getSession().setAttribute(USER_LOGIN_STATE, safetyUser);

它的意思就是将其保存在,session服务器中

而后续前端所携带的cookie中就有这个 通过session的key我们就能获取到用户信息!

搞懂Session就是现在!

以上 就是 刚刚的login功能,通过 Cookie 中 JSESSIONID 获取到的用户信息

而所谓的注销则是移除session中的数据

/**
 * 用户注销
 * @param request
 */
@Override
public int userLogout(HttpServletRequest request) {
// 移除登录态
request.getSession().removeAttribute(USER_LOGIN_STATE);
return 1;
}

Session的问题

细心的小伙伴应该就会发现,session应该也有问题吧,没错 我们看到session就是保存在服务器中的,而session代表的是一次会话,无论是在分布式的应用场景中又或者服务器重启后都会面临session丢失的问题!


分布式场景如下:


搞懂Session就是现在!

保存在不同的服务中无法共享session!

也就是说A服务器存储一个用户的服务,当我们网购的时候打开订单时(此时在B服务器) 但是B服务器 并不认识 A服务器中记载的session

不知道读者能不能理解!!!

Redis+Session

搞懂Session就是现在!

没错通过引入的redis,我们改变了session的存储模式

由以前的存储在服务器上的模式,更改为存储在数据库中

那么你看哈,引入redis 我们肯定需要下载redis 对吧

下载也很简单,我们如果没有服务器的话可以下载redis Windows 版本 地址如下:

github.com/MicrosoftAr…

当然,如果您电脑中有reids 那么可以忽略这一步!


下面我们已经下载好了,接下来该怎么办呢? 别急、如果我们想要在spring项目中使用redis 只需要引入一下依赖就好了!

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
  <version>2.6.4</version>
</dependency>

不知道大家还记不记的starter的命名格式呢?

  1. spring-boot-starter-xx 表示这是一个spring官方的starter
  2. xx-spring-boot-starter 这是指非spring官方的starter

也就是说明,上一个依赖是spring官方封装的starter

除此之外还有一些第三方的封装的redis 比如 redssion(适合分布式)jedis (速度快)

等等……

我们引入了redis 的依赖,表面我们已经可以将数据写入session了对吧。

这里,如果大家学过redis的话,知道读写命令 可能会将session 自己手动写入redis ~

但是,这么简单的事情,肯定会有别人帮我们考虑到!

所以我们还需要引入一个依赖:

<!-- https://mvnrepository.com/artifact/org.springframework.session/spring-session-data-redis -->
<dependency>
  <groupId>org.springframework.session</groupId>
  <artifactId>spring-session-data-redis</artifactId>
  <version>2.6.3</version>
</dependency>

这个依赖的作用就是,我们不需要执行任何操作,当我们保存在session中的数据,会经过上面的这个依赖,它会自动帮我们写入redis中,我们只需要做的就是在yaml中配置redis:

spring:
  redis:
    port: 6379
    host: localhost
    database: 1

jwt与session的区别

其实jwt与session最大的区别就是jwt的无状态性

那么什么是无状态性呢?就是说我们使用它来进行存储更加的轻量化,几乎不占用内存只是存储在前端的东西多点!,你可以将jwt理解成一个session整体(key+用户信息)

没错 前后端的交互都会携带着jwt 我们可以通过jwt 直接获取到用户数据

当然只有key+用户信息是不安全的,所以完整的jwt还会包含着加密的数据~

感兴趣可以看下jwt由哪三部分组成~ 我就不讲解了、因为这些都能够在网上搜到、讲解的意义不大!

想到这里你应该就能明白jwt的使用场景了

  1. 轻量化、不占用内存
  2. 无序、构造简单
  3. 还有一点 jwt 更多的是跨域的作用!

但是在实际的应用场景中还是session+redis更加适用!

因为虽然session相比jwt失去了简单性、但是session 的方式更加的灵活(jwt的生成无法修改)即使这样会占用部分内存。

但这点内存相比起灵活性,显得微不足道!

结尾

本篇完整就到此结束了~

我是荔枝程序员、一名大三的在校生~

作者继续找实习中求内推!

转载自:https://juejin.cn/post/7224097010633424952
评论
请登录