当前位置: 首页 > news >正文

【easy视频 | day01】项目了解 + 登录注册 + 使用 token 作为客户端请求令牌

文章目录

  • 前言
  • 完成任务
    • 1. 项目了解
    • 2. 登录注册
      • 2.1 创建数据表
      • 2.2 验证码
        • 如果使用 Session 存储验证码:
        • 不用 Session 存储验证码,用 Redis 会有什么问题?
      • 2.3 注册功能
      • 2.4 登录功能
      • 2.5 自动登录
      • 2.6 退出登录
  • 总结

在这里插入图片描述

前言

本项目非原创,我只是个小小白,跟随 b 站脚步,找到老罗的这个项目,视频来源于:
高仿B站(单服务版) springboot项目实战 easylive

本人不分享项目源码,支持项目付费!!!

完成任务

1. 项目了解

这是一个仿 b 站的项目,页面分为客户端和后台管理端,可发布视频,在线互动(评论、点赞、投币、发弹幕),后台管理对视频进行审核。

项目采用微服务架构构建,系统架构图:在这里插入图片描述

  • 正常线上部署会有 nginx 集群,本地上不存在 nginx 集群,直接就是:前端 ——> 网关。
  • 有很多个服务,服务跑起来后,每个服务有一个端口,但是这些服务的端口都不对外,对外的端口只有一个,就是 gateway 的端口
  • 服务与服务之间存在相互调用
  • Nacos 实现服务发现注册、作为配置中心。微服务部署加上 nginx 集群的情况下,将每个的配置抽离出来,放在一个配置中心进行配置,修改的时候不用一个个地去改,只需要修改配置中心。

2. 登录注册

2.1 创建数据表

根据该系统的用户特点,创建用户数据表。

为什么用邮箱发送验证码 ,而不使用手机号 ?
手机号发送验证码需要做财务报表,需要付费;邮箱目前接收验证码不需要付费。对于一个小型的项目,使用邮箱验证码就足够了。

注意:创建表字段后,某些字段可设置不为 NULL、主键、默认值;还需要设计必要的索引

2.2 验证码

如果使用 Session 存储验证码:

在这里插入图片描述
后端将生成的验证码 code 保存到 Session 会话中,当前端调用获取验证码的该接口时,响应头 Set-Cookie 中会包含 JSESSIONID :
在这里插入图片描述
如果此时,在进行 register 注册时,校验所填的验证码是否与刚刚存入 Session 的验证码相同,发起的请求中,也会携带这个 JSESSIONID:
在这里插入图片描述
JSESSIONID 就是一个会话的标记,使用 Session 会返回一个 JSESSIONID 来标记这个会话,下一次请求时,就会携带这个 JSESSIONID,判断这两个请求是否是同一个会话发出来的(会话可认为是一个浏览器,或者说新开的一个浏览器页面)。如果是同一个会话,校验验证码时就会获取存入当前会话 Session 中的验证码与前端填入的验证码进行比较;如果不是同一个会话,那么获取验证码请求和注册请求都不是同一个 JSESSIONID,那么就不可能从 Session 中获取到刚刚存入的验证码。

不用 Session 存储验证码,用 Redis 会有什么问题?

在这里插入图片描述
这里请求验证码时,将验证码保存在 Redis 中,设置过期时间为 10 分钟。

注册时,获取 Redis 中的验证码与前端传入的验证码进行比对:
在这里插入图片描述
比对成功,返回 true;不成功,返回 false。
但是,
这里有一个问题,当用户 A 获取验证码 a 后,将 a 存入 Redis;此时,另外一个用户 B 也获取验证码,得到验证码 b ,Redis 会将最新获得的验证码 b 存入,遮蔽掉先前存入的验证码 a。用户 A 输入他获得的验证码 a 进行校验,后端就会从 Redis 中取出最新获得的 b 与之校验
,用户 A 就发现不匹配,就会觉得疑惑:明明输入是正确的,为什么就是不匹配呢?
原因就是 Redis 中存储验证码的 key 是定死了的,就是 “checkCode”,全站所有人都用的这一个 key,每个人请求一下获取验证码的接口,这个 key 的值就更新了。它不是一个用户的唯一标识
所以说,直接这样使用 Redis 来存储验证码,是不可行的

但就是要用 Redis 来存储验证码,该怎么实现呢 ?
让每个用户请求验证码时,存入 Redis 的 key 是唯一的,能唯一标识这个用户。可以随机生成一个随机数作为每个用户验证码的 key,返回客户端数据时,将对应的 key 也和验证码图片一起返回
Redis 保存、获取和清除验证码的方法:
在这里插入图片描述

UUID:是 Java 中一个主要为对象生成一个唯一标识符的类
randomUUTD():生成一个随机的 UUID 对象,由 128 位数字组成,通常由 32 位十六进制表示,中间用破折号连接。
controller 层调用:
在这里插入图片描述

2.3 注册功能

先看 contoller 层中的参数:
在这里插入图片描述
这里直接使用注解对方法参数进行校验。要使用 @NotEmpty、@Email、@Size 这些注解,需要在 Controller 类上加上 @Validated 注解。
@NotEmpty: 确保参数不为空。
@Email: 确保字符串是一个有效的电子邮件地址。
@Size: 确保字符串的长度不超过指定的最大值。
@Pattern: 确保字符串符合指定的正则表达式。
密码的正则表达式通常是,至少包含一个数字和一个英文字母,密码长度在 8~18 之间,可以包含特殊字符:

public static final String REGEX_PASSWORD = "^(?=.*\\d)(?=.*[a-zA-Z])[\\da-zA-Z~!@#$%^&*_]{8,18}$";

在这里插入图片描述
service 层实现:
在这里插入图片描述
用户 ID 使用工具类方法中,随机生成字符串来实现:
在这里插入图片描述
第一个生成指定长度的字符串,可以包含字母和数字;第二个生成指定长度的字符串,不能包含字母。用户 ID 不需要字母,使用的是第二个。

设置用户密码,使用 MD5 加密:
在这里插入图片描述
这里直接使用 Apache 库中的 DigestUtils 类,计算给定字符串的 MD5 值。

2.4 登录功能

controller 层:
在这里插入图片描述
需要获取用户的 IP 地址,通过 HttpServletRequest 来获取用户 ip:

protected String getIpAddr() {HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();String ip = request.getHeader("x-forwarded-for");if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {// 多次反向代理后会有多个ip值,第一个ip才是真实ipif (ip.indexOf(",") != -1) {ip = ip.split(",")[0];}}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("HTTP_CLIENT_IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("HTTP_X_FORWARDED_FOR");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("X-Real-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();}return ip;}

sevice 层:
在这里插入图片描述
之前是使用 Session 来存储用户登录后的标识,在这里使用 token 来作为用户标识,以便于用户登录后,无需再重新登录,可以继续访问。
这里返回的 TokenUserInfoDto 中除了用户相关信息,还有 token 及其过期时间
在这里插入图片描述
@JsonIgnoreProperties(ignoreUnknown = true)注解:无论传入的JSON数据中是否包含类中未定义的属性,这些属性都会被忽略,而不会导致反序列化失败。在这里非常有用,如果说这个类中添加了其它属性,这个注解能保证数据的反序列化不会失败。

Redis 中存储 token 和用户信息,设置 token 值及其过期时间:
在这里插入图片描述
还有一步,将这个 token 手动地存入到 Cookie 中:
在这里插入图片描述
其实,获得 tokenUserInfoDto 后可以直接返回的,返回给前端后,前端去存放这个 token。但是为了保险,我们也可以像 Session 一样,Session 会在 Cookie 中存放一个 JSESSIONID,这其实就是服务端的工作。我们也可以将 token 存放在 Session 中:
在这里插入图片描述
成功访问 login 接口后,可看到 Cookie 中会有 token :
在这里插入图片描述
这样的话,当前用户再次访问其它接口,就不需要前端参与,Cookie 会自动将 token 携带过来

如果服务端还要获取 token 的话,直接使用 Response 不太方便,需要循环寻找,因为 Cookie 中有很多东西,获取 Cookie 得到的是一个数组,还需要遍历数组才能拿到 token。 但是,前端会从 Cookie 里把 token 解析出来,然后放到 head 头中带过来,这时候,在后端,就可以通过 @RequestHeader(“token”) 拿到 token。

登录最后,不能忘记还要清理掉 Redis 中的 验证码,token 可清理也可不清理:
在这里插入图片描述

2.5 自动登录

用户第一次成功登录后,Cookie 中会存在一个 token,设置的有效期为 7 天,7 天以内打开这个页面,应该是自动登录的:
在这里插入图片描述
如果是 7 天以内,再次登录,还需要再此执行 saveTokenInfo,重新生成一个 token,并重新开始计算时间:
在这里插入图片描述
并将这个重新生成的 token 存入 Cookie 中。

2.6 退出登录

在这里插入图片描述
退出登录,需要做的就是清理掉 Cookie 和 Redis 中的 token:
在这里插入图片描述
在这里插入图片描述

总结

一般来说,一个项目的登录注册功能,往往是这个项目动手写代码时第一个要做的功能。这部分功能包括验证码获取、注册、登录、自动登录、退出登录等。这段功能理解起来并不复杂,重点就是对 Redis 数据的操作、细节的把控、以及代码书写规范
在老罗的这个项目里,通过登录注册功能就可以学到很多以前不太了解的知识:尤其是 token 的使用,Session 的理解

相关文章:

【easy视频 | day01】项目了解 + 登录注册 + 使用 token 作为客户端请求令牌

文章目录 前言完成任务1. 项目了解2. 登录注册2.1 创建数据表2.2 验证码如果使用 Session 存储验证码:不用 Session 存储验证码,用 Redis 会有什么问题? 2.3 注册功能2.4 登录功能2.5 自动登录2.6 退出登录 总结 前言 本项目非原创,我只是个…...

使用elasticdump导出/导入 -- ES数据

导出指定索引数据到指定文件夹: ./elasticdump --inputhttp://用户:密码IP:9201/索引名字 --output导出路径/out.json --typedata 将导出的文件导入 ./elasticdump --input路径/out.json --outputhttp://账号:密码IP:9201/索引名称 --typedata --fileTypejson 【el…...

React + TypeScript 复杂布局开发实战

React TypeScript 复杂布局开发实战 一、项目架构设计(基于最新技术栈) 1.1 技术选型与工程创建 # 使用Vite 5.x React 19 TypeScript 5.4 npx create-vitelatest power-designer-ui --template react-ts cd power-designer-ui && npm inst…...

工业AR眼镜的‘芯’动力:FPC让制造更智能【新立电子】

随着增强现实(AR)技术的快速发展,工业AR智能眼镜也正逐步成为制造业领域的重要工具。它不仅为现场工作人员提供了视觉辅助,还极大地提升了远程协助的效率、优化了仓储管理。新立电子其高性能的FPC产品在AI眼镜中的应用&#xff0c…...

mapbox实现添加历史轨迹,并进行动画播放效果

1、引入播放插件类 https://download.csdn.net/download/qq_48795482/90437319 2、添加图层 drawRouteLine(resData, layerType) {console.log("调用了轨迹线函数", resData);var jsondata {type: "FeatureCollection",features: [],};var linejsondat…...

最好Wordpree+Apache+PHP安装教程

前提需要 PHP的安装最少需要7.4以上Mysql的安装,直接默认最新版就行APache服务器(HTTP服务器,只有用这个你的软件才能在服务器上运行) 安装apache 安装 sudo apt install apache2查看防火墙 sudo ufw app list如果有 Apache那…...

Windows搭建jenkins服务

jenkins下载 官网:https://www.jenkins.io 中文文档:Jenkins 直接可下载网址:Jenkins 的安装和设置 安装前准备 在安装 jenkins 之前要先确保电脑上是否已配置过 Java 的环境变量,可调出命令窗口(win R 再输入 cmd&…...

鸿蒙-AVPlayer

compileVersion 5.0.2(14) 音频播放 import media from ohos.multimedia.media; import common from ohos.app.ability.common; import { BusinessError } from ohos.base;Entry Component struct AudioPlayer {private avPlayer: media.AVPlayer | nu…...

解决单元测试 mock final类报错

文章目录 前言解决单元测试 mock final类报错1. 报错原因2. 解决方案3. 示例demo4. 扩展 前言 如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。   而且听说点赞的人每天的运气都不会太差&#xff0…...

Kafka消费者相关

Kafka生产者相关-CSDN博客 消费者消费数据基本流程 package com.hrui;import org.apache.kafka.clients.consumer.ConsumerConfig; import org.apache.kafka.clients.consumer.ConsumerRecord; import org.apache.kafka.clients.consumer.ConsumerRecords; import org.apache…...

Vue nextTick原理回顾

nextTick就是将异步函数放在下一次实践循环的微任务队列中执行 实现原理比较简单,极简版本: function myNextTick(cb){let p;pPromise.resolve().then(cb)return cb?p:Promise.resolve() }复杂版本,考虑异步函数入队、执行锁、兼容处理 l…...

JavaWeb登录认证

在Web系统中,如果没有登录功能和登录认证,是可以直接访问到Web系统的后台的。 这是不安全的,所以我们今天的主题就是登录认证。最终要实现的效果是: 如果用户名密码错误,不允许登录系统。如果用户名和密码都正确&…...

半导体制造工艺(二)光刻工艺—掩模版

在上文中我们已经简单概述了光刻工艺的大致流程。接下来将会介绍在光刻工艺中所需用到的必备材料以及设备。例如掩模版、光刻胶、匀胶机、光刻机等等。由于需要保持讲述工艺的完整性以及流畅,每一个都需要涉及,所以每次仅是侧重点不同。此篇主要讲述的是…...

计算机视觉算法实战——高精度分割(主页有源码)

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​ ​​​ 1. 高精度分割领域简介✨✨ 图像分割是计算机视觉中的核心任务之一,其目标是将图像划分为多个语义区域,并为…...

DeepSeek-R1-Zero:基于基础模型的强化学习

注:此文章内容均节选自充电了么创始人,CEO兼CTO陈敬雷老师的新书《自然语言处理原理与实战》(人工智能科学与技术丛书)【陈敬雷编著】【清华大学出版社】 文章目录 DeepSeek大模型技术系列四DeepSeek大模型技术系列四》DeepSeek-…...

判断一个文件中以三个#号开头有多少行的shell脚本怎么写

在Linux中,你可以使用grep命令结合正则表达式来统计一个文件中以三个#号开头的行数。以下是一个简单的命令: grep -c ^### filename这里的grep是搜索工具,-c选项表示统计匹配的行数,###是正则表达式,表示行…...

PHP如何与HTML结合使用?

PHP与HTML结合使用的主要方式是通过在HTML文件中嵌入PHP代码&#xff0c;从而实现动态内容的生成和网页的交互性。以下是详细的方法和最佳实践&#xff1a; 1. 嵌入PHP代码到HTML中 PHP代码可以直接嵌入到HTML文件中&#xff0c;通过<?php ?>标签来包裹PHP代码。服务…...

计算机网络之传输层(传输层的功能)

一、数据分段与重组 传输层从会话层接收数据&#xff0c;并将其分割成较小的数据段&#xff0c;以适应网络层的最大传输单元&#xff08;MTU&#xff09;限制。在目的端&#xff0c;传输层负责将这些数据段重新组合成原始数据&#xff0c;确保数据的完整性和正确性。 二、端口…...

矩阵碰一碰发视频源码搭建之,支持OEM

引言 阵碰一碰发视频" 技术凭借其便捷的交互方式和高效的传播能力&#xff0c;已成为品牌推广和内容创作的重要工具。为进一步提升视频传播效果&#xff0c;本文将深入探讨如何在矩阵碰一碰系统中集成 AI 文案生成功能&#xff0c;实现 "一碰即传 智能文案" 的…...

DeepSeek 2月27日技术突破:三大核心功能解析与行业影响

DeepSeek 2月27日技术突破&#xff1a;三大核心功能解析与行业影响 一、最新发布功能全景图 1. DualPipe&#xff1a;双向流水线并行革命 DualPipe是一项极具创新性的双向管道并行算法&#xff0c;旨在解决大规模模型训练过程中计算与通信效率低下的关键问题。在传统的模型训…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

第19节 Node.js Express 框架

Express 是一个为Node.js设计的web开发框架&#xff0c;它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用&#xff0c;和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

c++第七天 继承与派生2

这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分&#xff1a;派生类构造函数与析构函数 当创建一个派生类对象时&#xff0c;基类成员是如何初始化的&#xff1f; 1.当派生类对象创建的时候&#xff0c;基类成员的初始化顺序 …...

libfmt: 现代C++的格式化工具库介绍与酷炫功能

libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库&#xff0c;提供了高效、安全的文本格式化功能&#xff0c;是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全&#xff1a…...

在 Spring Boot 中使用 JSP

jsp&#xff1f; 好多年没用了。重新整一下 还费了点时间&#xff0c;记录一下。 项目结构&#xff1a; pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...

数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !

我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...

协议转换利器,profinet转ethercat网关的两大派系,各有千秋

随着工业以太网的发展&#xff0c;其高效、便捷、协议开放、易于冗余等诸多优点&#xff0c;被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口&#xff0c;具有实时性、开放性&#xff0c;使用TCP/IP和IT标准&#xff0c;符合基于工业以太网的…...

上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式

简介 在我的 QT/C 开发工作中&#xff0c;合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式&#xff1a;工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...

FFmpeg avformat_open_input函数分析

函数内部的总体流程如下&#xff1a; avformat_open_input 精简后的代码如下&#xff1a; int avformat_open_input(AVFormatContext **ps, const char *filename,ff_const59 AVInputFormat *fmt, AVDictionary **options) {AVFormatContext *s *ps;int i, ret 0;AVDictio…...