LOADING

加载过慢请开启缓存 浏览器默认开启

🚀 青橙商城全栈项目实战(一):用户认证与数据持久化底层原理

用户认证与数据持久化底层原理

在商城项目的阶段二开发中,核心任务是实现用户注册与登录,并建立安全的网络通信通道。本篇笔记详细梳理了这其中的核心技术和底层原理。


一、 MyBatis-Plus 的数据持久化原理

MyBatis-Plus (简称 MP) 是对 MyBatis 的无侵入增强工具,其核心原理是通过 Java 反射机制注解声明 自动完成对象关系映射 (ORM)。

1. 实体与数据库的映射

MP 通过在实体类上添加注解来识别数据库映射规则:

  • @TableName("users"):指定该类对应的数据库表为 users
  • BaseEntity 中的主键属性上标注了 @TableId(type = IdType.AUTO),声明主键为自增类型。
  • 类中的驼峰属性(如 createTime)会被 MP 的自动驼峰命名规则 (map-underline-to-camel-case: true) 自动映射为下划线形式的数据库列名(create_time)。

2. BaseMapper 的通用 CRUD 注入

@Mapper
public interface UserMapper extends BaseMapper<User> {}

在 Spring Boot 启动时,MP 框架会扫描继承了 BaseMapper<T> 的接口,并根据泛型 T (即 User 实体类) 通过反射获取其所有字段,在内存中动态生成一系列常用的 SQL 语句(如 INSERT INTO users ...)。
当我们在 Service 中调用 baseMapper.insert(user) 时,底层的 MyBatis 执行器会执行插入并使用 JDBC 的 getGeneratedKeys 方法,将数据库生成的自增 ID 回填到传入 of user 对象的 id 属性中。


二、 密码加密存储与 BCrypt 算法

数据库绝对不能明文存储用户的密码。青橙商城采用 BCrypt 强哈希算法对密码进行加密。

1. 为什么不使用 MD5 或 SHA-256?

MD5 和 SHA-256 是快速哈希算法,极易受到**彩虹表(Rainbow Table)**的碰撞攻击和 GPU 暴力破解。而 BCrypt 是单向、慢速哈希算法,能显著增加破解成本。

2. BCrypt 的核心原理

  • 自动加盐(Salt):BCrypt 每次加密时都会在底层随机生成一个唯一的“盐值”(Salt),并与密码拼合。这意味着:相同的明文密码,每次加密得到的密文完全不同。
  • 结构化密文:密文形如 $2a$10$DnPNUNqh...
    • $2a$ 代表算法版本。
    • $10$ 代表计算强度(即哈希迭代次数为 $2^{10}$ 次)。
    • 随后的前 22 个字符是随机生成的盐值。
    • 剩余字符是混合盐值后哈希生成的密文。

3. 代码验证逻辑

  • 加密
    user.setPassword(passwordEncoder.encode(password));
    
  • 校验:由于每次生成的密文不同,不能直接用 = 比较。必须用 matches 方法:
    passwordEncoder.matches(plainPassword, hashedPassword);
    
    BCrypt 会从 hashedPassword 中读取当初的加密盐值,用这个盐值对 plainPassword 进行哈希,最后比对生成的密文。

三、 JWT (JSON Web Token) 无状态认证原理

在前后端分离架构下,不再推荐使用传统的 Session-Cookie 机制,而是采用基于 JWT 的无状态身份验证。

1. JWT 的三部分组成

JWT 是一个由 . 连接的三段式 Base64 字符串:

  1. Header(头部):描述 Token 的元数据,通常为签名算法名称(如 HS384)和令牌类型(JWT)。
  2. Payload(载荷):存放声明数据(Claims),包括用户名(sub)、签发时间(iat)、过期时间(exp)等非敏感用户信息。
  3. Signature(签名):由 HeaderPayload 的 Base64 字符串拼合后,使用服务器保密的 Key 和算法进行哈希计算生成的签名。

2. 无状态的生命周期

  1. 用户在前端输入用户名和密码登录。
  2. 后端校验密码通过后,使用私钥签名生成 JWT 字符串,并返回给前端。
  3. 前端将 JWT 存储在 LocalStorage 中,并载入状态管理(Pinia/Vuex)。
  4. 前端此后的每次 HTTP 请求,都在 Header 中携带 Authorization: Bearer <Token>
  5. 后端接收到请求后解析 Token,使用本地私钥验证 Signature。无需查询数据库或 Redis 验证 Session,直接在内存中判定 Token 是否合法。

四、 跨域代理(CORS)与请求转发

由于浏览器的同源策略(Same-Origin Policy),运行在 http://localhost:3000 的管理端前端直接向 http://localhost:8080 的后端发送请求会被拦截。本项目在开发阶段使用 Vite 的服务器代理功能解决跨域。

1. Axios 封装与基地址

在管理端 request.ts 中,配置 Axios 的统一前缀为 /api

const service = axios.create({
  baseURL: '/api',
  timeout: 10000
});

2. Vite 代理转发

vite.config.ts 中,配置 dev 服务器代理:

server: {
  port: 3000,
  proxy: {
    '/api': {
      target: 'http://localhost:8080',
      changeOrigin: true
    }
  }
}
  • 工作流:前端请求发送至 http://localhost:3000/api/auth/login
  • 代理拦截:Vite 开发服务器发现路径以 /api 开头,便代为将请求转发至后端的 http://localhost:8080/api/auth/login
  • 避开跨域:因为浏览器是与同源的 localhost:3000 通信,而代理服务器与后端服务器之间的请求不受同源策略限制,从而绕过了跨域限制。