跳到主要内容

认证授权

概述

系统采用 JWT Token 认证方案,基于 OAuth2 协议实现。用户端认证入口为 AppAuthController(路径前缀 /member/auth/),支持多种登录方式。

认证流程

用户发起登录请求

后端校验凭据(手机号+密码 / 验证码 / 社交授权码)

创建 OAuth2 AccessToken + RefreshToken

返回 { accessToken, refreshToken, openid }

前端保存 Token 到本地存储

后续请求在 Header 中携带 Authorization: Bearer {accessToken}

登录方式

1. 手机号 + 密码登录

接口POST /app-api/member/auth/login

// 请求体
{
"mobile": "13800138000",
"password": "123456",
"socialType": null, // 可选,同时绑定社交账号
"socialCode": null,
"socialState": null
}

处理流程

  1. 根据手机号查找用户
  2. 校验密码(BCrypt 加密比对)
  3. socialType 非空,同时绑定社交用户
  4. 创建 Token 令牌
  5. 记录登录日志

2. 手机号 + 验证码登录

发送验证码POST /app-api/member/auth/send-sms-code

{ "mobile": "13800138000" }

验证码登录POST /app-api/member/auth/sms-login

{
"mobile": "13800138000",
"code": "1234",
"loginType": 10, // 10=普通验证码登录,20=一键快捷登录
"socialType": null, // 可选
"socialCode": null,
"socialState": null
}

处理流程

  1. 校验短信验证码(测试号 18612982956 跳过验证)
  2. 自动创建用户(如不存在)
  3. 校验用户状态(是否被禁用)
  4. 创建 Token 令牌

3. 微信小程序登录

获取 openIdPOST /app-api/member/auth/get-wx-openid

{ "loginCode": "微信临时登录凭证" }

一键登录POST /app-api/member/auth/weixin-mini-app-login

{
"loginCode": "微信临时登录凭证",
"phoneCode": "手机号授权码" // 可选,获取绑定手机号
}

处理流程

  1. 通过 loginCode 调用微信接口获取 sessionKey + openId
  2. 根据 openId 查找已绑定用户,不存在则自动创建
  3. 若提供了 phoneCode,解密获取手机号并绑定
  4. 创建 Token 令牌,返回中包含 openid

4. 社交快捷登录

获取授权跳转 URLGET /app-api/member/auth/social-auth-redirect

参数说明
type社交类型枚举值
redirectUri回调地址

授权码登录POST /app-api/member/auth/social-login

{
"type": 1,
"code": "社交授权码",
"state": "防 CSRF 状态值"
}

处理流程

  1. 通过 code 获取社交用户信息
  2. 若已绑定用户 → 直接登录
  3. 若未绑定 → 自动创建用户并绑定
  4. 创建 Token 令牌

Token 机制

令牌结构

字段说明
accessToken访问令牌,用于 API 认证
refreshToken刷新令牌,用于获取新的 accessToken
openid微信 openId(仅微信登录时返回)

令牌刷新

接口POST /app-api/member/auth/refresh-token

{ "refreshToken": "刷新令牌" }

前端自动刷新逻辑

请求返回 401

检查是否为 refresh-token 请求本身 → 是 → 直接拒绝

检查 isRefreshToken 标志
↓ 否
设置 isRefreshToken = true

调用 refresh-token 接口
↓ 成功
更新 Token → 回放队列中的请求 → isRefreshToken = false
↓ 失败
清空队列 → 清除登录状态 → 跳转登录页

并发请求处理:当多个请求同时返回 401 时,只有第一个请求执行刷新操作,其余请求进入等待队列。刷新成功后统一回放。

登出

接口POST /app-api/member/auth/logout

前端调用 setToken('') 清除本地 Token,同时触发:

  1. 移除 StorageKeyEnum.TOKEN
  2. 移除 StorageKeyEnum.REFRESH_TOKEN
  3. 清空用户信息
  4. 设置 isLogin = false

请求认证机制

请求头

Header说明
AuthorizationBearer {accessToken} 访问令牌
terminal终端类型枚举(10=小程序,11=公众号,20=H5,31=App)

@PermitAll 注解

标记为 @PermitAll 的接口无需携带 Token,所有认证相关接口均使用此注解:

@PostMapping("/login")
@Operation(summary = "使用手机 + 密码登录")
@PermitAll
public CommonResult<AppAuthLoginRespVO> login(...) { }

登录日志

每次登录操作均记录登录日志,包含以下信息:

字段说明
用户 ID登录用户
手机号登录手机号
登录类型LOGIN_MOBILE / LOGIN_SMS / LOGIN_SOCIAL
登录结果成功 / 用户禁用 / 密码错误 等
用户 IP客户端 IP
User Agent浏览器信息
终端terminal 枚举值

短信验证码配置

yudao:
sms-code:
expire-times: 10m # 验证码有效期 10 分钟
send-frequency: 1m # 发送间隔最少 1 分钟
send-maximum-quantity-per-day: 10 # 每日最多发送 10 条
begin-code: 0000 # 验证码范围起始
end-code: 9999 # 验证码范围结束

前端登录状态管理

登录成功后的连锁操作

// store.setToken() 内部流程
this.isLogin = true
uni.setStorageSync(StorageKeyEnum.TOKEN, token)
uni.setStorageSync(StorageKeyEnum.REFRESH_TOKEN, refreshToken)
this.user = await getUserInfoApi() // 拉取用户信息
await useIM().login() // 登录腾讯云 IM

被踢下线处理

当同一账号在其他设备登录时,IM SDK 触发 KICKED_OUT 事件:

const onKickedOut = () => {
showToast('账号在其他设备登录', async () => {
useStore().setToken() // 清除本地 Token
await useIM().logout() // 登出 IM
relaunchApp() // 重启应用
})
}

微信 JS-SDK 签名

用于微信分享、支付等 JS-SDK 功能:

接口POST /app-api/member/auth/create-weixin-jsapi-signature?url=xxx

返回签名信息:

{
"appId": "wx...",
"timestamp": 1234567890,
"nonceStr": "xxx",
"signature": "xxx"
}