会员认证
XYGo Admin 2025-02-20 57 次阅读
会员登录注册与 JWT Token 机制
会员认证
认证体系
会员认证独立于后台管理员,使用不同的 Token Header:
| 对比项 | 后台管理员 | 前台会员 |
|---|---|---|
| Token Header | Authorization: Bearer |
Xy-User-Token |
| 中间件 | AdminAuth | MemberAuth |
| Store | useUserStore | useMemberStore |
| 路由前缀 | /admin |
/member |
登录方式
系统支持三种登录方式:
| 方式 | 适用场景 | 接口路径 | 获取方式 |
|---|---|---|---|
| 账号密码登录 | Web 前台 | POST /member/auth/login |
用户名 + 密码 |
| 微信小程序登录 | 小程序 / 小游戏 | POST /wm/auth/login |
微信 code |
| 微信公众号登录 | 公众号 H5 网页 | GET /wm/oa/auth/url + GET /wm/oa/auth/callback |
OAuth2 授权 |
三种方式共享同一套会员体系(xy_member 表),登录后均返回 JWT Token,后续请求通过 Xy-User-Token Header 鉴权。
一、账号密码登录
1. 用户输入账号密码
2. 前端调用 POST /member/auth/login
3. 后端校验密码(bcrypt 加密比对)
4. 生成 JWT Token
5. 返回 Token + 用户信息
6. 前端存储到 useMemberStore(持久化)
7. 后续请求自动注入 Xy-User-Token Header
二、微信小程序登录
适用于微信小程序、小游戏场景,用户无需输入账号密码,通过微信授权一键登录。
流程
1. 小程序端调用 uni.login() 获取微信临时 code
2. 将 code 发送到 POST /wm/auth/login
3. 后端从 xy_sys_config 读取 we_mapp 分组的 appid / appsecret
4. 调用微信 jscode2session 接口,用 code 换取 openid + session_key
5. 按 platform+openid 查询 xy_member_oauth 表
6. 若用户不存在则自动注册(用户名 wx_xxx、默认昵称"微信用户")
7. 复用 token.GenerateMember 生成 JWT Token
8. 返回 {token, expiresIn, isNew}
接口定义
POST /wm/auth/login
请求参数:
json
{
"code": "微信登录临时code"
}
响应:
json
{
"code": 0,
"data": {
"token": "eyJhbGciOi...",
"expiresIn": 7200,
"isNew": true
}
}
后台配置
在后台管理 → 系统配置 → 小程序配置中填写:
- 微信小程序 AppID(wmapp_appid)
- 微信小程序 AppSecret(wmapp_secret)
白名单
/wm/auth/login 已加入 MemberAuth 中间件白名单,无需携带 Token 即可访问。
三、微信公众号登录(OAuth2 网页授权)
适用于微信公众号内 H5 网页,用户在微信内打开页面后通过 OAuth2 授权登录,可获取微信昵称和头像。
前置条件
- 需要认证的服务号(或微信测试号)
- 在微信公众平台 → 设置与开发 → 公众号设置 → 功能设置中配置网页授权域名
流程
1. H5 前端调用 GET /wm/oa/auth/url?redirect=前端回跳地址
2. 后端从 xy_sys_config 读取 we_oa 分组的 appid
3. 拼接微信授权 URL 并返回
4. 前端跳转到微信授权页面(window.location.href = url)
5. 用户同意授权后,微信 302 回调到 /wm/oa/auth/callback?code=xxx
6. 后端用 code 换取 access_token + openid
7. 用 access_token 调用微信 userinfo 接口获取昵称/头像
8. 按 platform+openid 查询 xy_member_oauth 表
9. 若用户不存在则自动注册(携带微信昵称和头像)
10. 复用 token.GenerateMember 生成 JWT Token
11. 返回 {token, expiresIn, isNew}
接口定义
GET /wm/oa/auth/url
请求参数:
| 参数 | 说明 |
|---|---|
| redirect | 授权完成后前端回跳地址 |
响应:
json
{
"code": 0,
"data": {
"url": "https://open.weixin.qq.com/connect/oauth2/authorize?appid=..."
}
}
GET /wm/oa/auth/callback
请求参数(微信回调自动携带):
| 参数 | 说明 |
|---|---|
| code | 微信授权码 |
| state | 防伪校验值 |
响应:
json
{
"code": 0,
"data": {
"token": "eyJhbGciOi...",
"expiresIn": 7200,
"isNew": true
}
}
后台配置
在后台管理 → 系统配置 → 公众号配置中填写:
- 公众号 AppID(weoa_appid)
- 公众号 AppSecret(weoa_secret)
- 公众号 Token(weoa_token)—— 用于消息验证
白名单
/wm/oa/auth/url 和 /wm/oa/auth/callback 均已加入 MemberAuth 中间件白名单。
注册流程
1. 用户填写注册信息(用户名、密码、手机号等)
2. 前端调用 POST /member/auth/register
3. 后端校验唯一性(用户名、手机号不重复)
4. 生成 salt,加密密码
5. 写入 member 表
6. 自动登录,返回 Token
数据库字段
第三方登录信息存储在独立的 xy_member_oauth 表中,与 xy_member 一对多关联:
| 字段 | 类型 | 说明 |
|---|---|---|
| member_id | bigint | 关联 xy_member.id |
| platform | varchar(32) | 平台标识:wechat_mapp / wechat_oa / qq / alipay 等 |
| openid | varchar(128) | 该平台的 openid |
| unionid | varchar(128) | unionid(可选) |
| session_key | varchar(128) | 小程序 session_key |
| nickname | varchar(100) | 该平台的昵称 |
| avatar | varchar(500) | 该平台的头像 |
| extra | text | 扩展 JSON |
采用独立 oauth 表的好处:新增任何第三方登录只需 INSERT 一行记录,无需修改 xy_member 表结构。同一会员可绑定多个平台。
获取用户信息
登录后可通过以下接口获取当前用户信息:
GET /wm/auth/profile(需携带 Xy-User-Token)
响应:
json
{
"code": 0,
"data": {
"id": 1,
"nickname": "微信用户",
"avatar": "",
"score": 0,
"money": 0,
"level": 1
}
}
前端使用(UniApp)
javascript
import { useUserStore } from '@/store/user'
const store = useUserStore()
// 小程序登录
const loginRes = await new Promise((resolve, reject) => {
uni.login({ provider: 'weixin', success: resolve, fail: reject })
})
const data = await wxMappLogin(loginRes.code)
store.setToken(data.token)
// 公众号登录(H5)
const data = await oaAuthUrl(redirect)
window.location.href = data.url
// 获取用户信息
await store.fetchProfile()
// 登出
store.logout()
路由守卫
会员中心页面需要登录才能访问,在路由守卫中检查:
- 访问
/user/*路径时检查会员 Token - 未登录跳转到
/user/login - 支持白名单配置(无需登录的页面)