系统概述

幽游网络验证是一套开箱即用的软件授权与会员管理系统。它对外暴露 RESTful API,你的软件(易语言、C#、Python、Go、Java 等任意能发 HTTP 请求的语言)按约定调用,就能拥有用户注册登录、会员校验、卡密兑换、心跳在线检测、商店充值等完整功能。

核心特点:前后端一体打包成单个可执行文件,丢到服务器就能跑,不需要额外前端服务器、不需要 Nginx 反代也能直接用。

系统架构

系统采用经典的三层架构:

  • 客户端层:你的软件通过 HTTPS 请求调用 API,请求体使用 RSA 加密 + MD5 签名保障安全
  • 服务端层:Go + Gin 构建的高性能后端,处理所有业务逻辑
  • 数据层:MySQL 存储业务数据,Redis 处理会话缓存和防重放

功能模块

模块 说明
用户系统邮箱注册/登录、双 Token 认证、改密、封禁控制
会员体系普通/高级/永久三档,有效期管理,过期自动降级
卡密系统批量生成卡密,支持 U 币卡/会员时长卡,兑换用行锁防并发
心跳系统客户端定时上报,服务端校验授权有效性,超时自动断线
商店系统U 币购买虚拟商品,原子事务保证一致性
签到系统每日签到奖励 U 币或会员时长
充值支付支持易支付、支付宝、微信,回调验签 + 幂等发币
定时任务会员过期回收、卡密过期回收、超时关单等自动化任务

环境准备

在开始部署之前,请确保你的服务器已安装以下软件:

必需软件

软件 版本要求 用途
MySQL5.6+存储用户、会员、订单等业务数据
Redis5.0+会话管理、防重放、缓存

可选软件

软件 用途
Go 1.22+如果需要从源码编译(推荐使用预编译二进制)
Nginx反向代理,用于域名访问和 HTTPS
Docker容器化部署(可选)
宝塔面板用户:可以在软件商店中一键安装 MySQL 和 Redis,无需手动配置。

配置文件

所有配置集中在 configs/config.yaml 文件中。以下是关键配置项说明:

MySQL 数据库配置

YAML
mysql:
  host: 127.0.0.1          # MySQL 服务器地址
  port: 3306               # MySQL 端口
  username: root           # 数据库用户名
  password: your_password  # 数据库密码(请修改为实际密码)
  database: youyou_auth    # 数据库名(无需手动创建,init 命令会自动创建)
  charset: utf8mb4         # 字符集(不要修改)
  max_idle_conns: 10       # 连接池最大空闲连接数
  max_open_conns: 100      # 连接池最大连接数
  conn_max_lifetime: 1h    # 连接最大存活时间
宝塔面板获取 MySQL 密码:登录宝塔面板 → 左侧菜单「数据库」→ 找到 root 密码或对应数据库的密码。

Redis 配置

YAML
redis:
  host: 127.0.0.1     # Redis 服务器地址
  port: 6379          # Redis 端口
  password: ""        # Redis 密码(宝塔默认无密码,设了密码就填这里)
  db: 0               # Redis 数据库编号(0-15)
  pool_size: 100      # 连接池大小

JWT 配置

YAML
jwt:
  secret: "youyou-auth-secret-key-change-me"  # 必须修改!用随机字符串
  issuer: "youyou-auth"
  access_expire: 2h        # Token 有效期
  refresh_expire: 168h     # Refresh Token 有效期(7 天)
安全提示:生产环境务必修改 jwt.secret 为随机字符串!可以使用 openssl rand -hex 32 生成。

邮件配置(用于注册验证码)

YAML
email:
  host: smtp.qq.com              # SMTP 服务器
  port: 465                      # SMTP 端口(SSL 用 465)
  username: your_email@qq.com    # 邮箱地址
  password: your_smtp_code       # SMTP 授权码(不是邮箱登录密码!)
  from_name: "幽游网络验证"
  from_addr: your_email@qq.com

QQ 邮箱获取 SMTP 授权码:登录 QQ 邮箱 → 设置 → 账户 → 找到「POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV 服务」→ 开启「IMAP/SMTP 服务」→ 按提示用手机发短信获取授权码。

服务配置

YAML
server:
  port: 8080        # 服务监听端口(需在安全组放行)
  mode: release     # release=生产模式 / debug=开发模式
  read_timeout: 10s
  write_timeout: 10s

安装与初始化

配置好 config.yaml 后,运行初始化命令创建数据库和管理员账号:

Bash
# 在项目根目录执行
go run cmd/init/main.go -config configs/config.yaml

# 或使用编译后的二进制文件
./youyou-auth-init -config configs/config.yaml

# 可选:自定义管理员账号
./youyou-auth-init -config configs/config.yaml -admin-user admin -admin-pass MyStr0ngP@ss

初始化命令会自动完成:

  1. 连接 MySQL — 使用 config.yaml 中的配置
  2. 创建数据库 — 自动创建 youyou_auth 数据库(如果不存在)
  3. 创建数据表 — 自动创建所有业务表(13 张表)
  4. 创建管理员账号 — 用户名 + 密码(bcrypt 加密存储)
  5. 输出凭证 — 显示管理员用户名和密码,请妥善保存!
初始化成功输出示例:
管理员用户名:admin
管理员密码:a1b2c3d4
昵称:超级管理员
重要:请妥善保管管理员用户名和密码!登录后可在后台创建应用,系统会自动生成 APPID/APPKEY 供客户端使用。

启动服务

初始化完成后,可以启动服务了。有三种方式:

方式一:直接运行(推荐新手)

Bash
# Linux
./youyou-auth -config configs/config.yaml

# Windows(双击运行)
youyou-auth-windows-amd64.exe

方式二:Systemd 服务(推荐生产环境)

Bash
# 创建 systemd 服务文件
cat > /etc/systemd/system/youyou-auth.service << 'EOF'
[Unit]
Description=YouYou Auth Service
After=network.target mysql.service redis.service

[Service]
Type=simple
WorkingDirectory=/www/wwwroot/youyou-auth
ExecStart=/www/wwwroot/youyou-auth/youyou-auth -config configs/config.yaml
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

# 启用并启动服务
systemctl daemon-reload
systemctl enable youyou-auth
systemctl start youyou-auth

# 查看状态
systemctl status youyou-auth

方式三:宝塔面板

在宝塔面板的「Go 项目管理器」或「Supervisor 管理器」中添加项目:

  • 执行命令:/www/wwwroot/youyou-auth/youyou-auth -config configs/config.yaml
  • 运行目录:/www/wwwroot/youyou-auth
  • 端口:8080

验证服务

Bash
# 健康检查
curl http://localhost:8080/health
# 返回: {"status":"ok","service":"youyou-auth"}

# Ping 测试
curl http://localhost:8080/ping
# 返回: {"pong":"ok"}
放行端口:记得在宝塔面板「安全」或云服务器安全组中放行 8080 端口!

一键安装模式

如果你不想手动编辑 config.yaml,系统提供了网页可视化安装向导。只需指定端口启动程序,打开浏览器即可完成数据库、Redis 和管理员账号的配置,特别适合初学者。

零配置启动:无需创建或编辑任何配置文件,所有设置通过网页表单完成,自动写入 config.yaml

第一步:上传程序文件

将下载好的程序文件(如 youyou-auth-linux-amd64)上传到服务器任意目录,例如 /www/wwwroot/youyou/。同时确保 configs/ 目录下没有 config.yaml 文件(如果之前生成过,请先删除或重命名)。

Bash
# 给程序添加执行权限
chmod +x /www/wwwroot/youyou/youyou-auth-linux-amd64

# 确认 configs 目录下没有 config.yaml(有则移走)
ls /www/wwwroot/youyou/configs/
# 如果看到 config.yaml,执行:
mv /www/wwwroot/youyou/configs/config.yaml /www/wwwroot/youyou/configs/config.yaml.bak

第二步:通过宝塔面板创建 Go 项目

在宝塔面板左侧菜单找到 「Go 项目管理」,点击 「添加项目」,按以下信息填写:

1
项目执行文件:选择你上传的程序文件路径,如 /www/wwwroot/youyou/youyou-auth-linux-amd64
2
项目名称:自定义,如 uuyzserver
3
项目端口:填写你希望监听的端口号,如 8899(可自定义,确保未被占用)
4
执行命令:填写 youyou-auth-linux-amd64 -port 8899(端口号与上一步一致)
5
运行用户:保持默认 root 即可(无特殊需求也可选 www
6
开机启动:建议勾选,服务器重启后自动运行
关键参数:执行命令中的 -port 8899 是必须的,它告诉程序监听 8899 端口。端口号可以自定义,但必须与「项目端口」保持一致。

第三步:打开安装向导页面

保存配置并启动项目后,在浏览器中访问:

URL
http://你的服务器IP:8899/

程序检测到 config.yaml 不存在,会自动跳转到安装向导页面 /install。你将看到一个美观的配置表单,包含以下三个部分:

MySQL 数据库配置

字段说明默认值示例
数据库主机MySQL 服务器地址127.0.0.1127.0.0.1
数据库端口MySQL 监听端口33063306
数据库名自动创建的数据库名称youyou_authyouyou_auth
表前缀所有表名的前缀(可选)(空)yy_
用户名MySQL 登录用户名root
密码MySQL 登录密码your_password

Redis 配置

字段说明默认值示例
Redis 主机Redis 服务器地址127.0.0.1127.0.0.1
Redis 端口Redis 监听端口63796379
Redis DB使用的数据库编号00
Redis 密码Redis 连接密码(可选)(空)your_redis_pass

管理员账号配置

字段说明默认值示例
域名 / IP系统对外访问地址(可选)(空)auth.example.com
管理入口路径后台管理页面路径adminadmin
管理员用户名后台登录用户名adminadmin
管理员密码后台登录密码(5-18 位)your_secure_pass

第四步:测试连接并确认安装

1
填写完 MySQL 信息后,点击 「测试连接」 按钮,确认数据库可以正常连通。如果连接失败,请检查 MySQL 是否已启动、用户名密码是否正确。
2
填写完 Redis 信息后,同样点击 「测试连接」 验证。
3
所有信息确认无误后,点击 「确认安装」。系统会自动完成以下操作:
  • 创建 MySQL 数据库(如果不存在)
  • 自动建表(20+ 张业务表,含默认签到奖励配置)
  • 创建管理员账号(密码加密存储)
  • 生成 configs/config.yaml 配置文件(含随机 JWT 密钥)
安装完成后:页面会提示安装成功。此时需要重启项目(在宝塔面板 Go 项目管理中点击重启),程序会读取新生成的 config.yaml 进入正常运行模式。重启后访问 http://你的IP:8899/admin 即可进入后台管理界面。

命令行方式(非宝塔用户)

如果你没有使用宝塔面板,也可以直接在终端运行:

Bash
# Linux / macOS
./youyou-auth-linux-amd64 -port 8899

# Windows
youyou-auth-windows-amd64.exe -port 8899

启动后同样在浏览器中访问 http://localhost:8899/ 即可进入安装向导。

安全提醒:安装向导页面会暴露数据库密码等敏感信息。安装完成后请务必通过 Nginx 反向代理绑定域名并配置 SSL 证书,不要直接将安装端口暴露到公网。如果已完成安装,删除 config.yaml 后重新启动会再次进入安装向导,请妥善保管配置文件。

Nginx 反向代理

如果你想用域名访问(如 api.yourdomain.com),可以配置 Nginx 反向代理:

Nginx
server {
    listen 80;
    server_name api.yourdomain.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

宝塔面板配置方法:网站 → 添加站点 → 设置 → 反向代理 → 目标 URL 填 http://127.0.0.1:8080,发送域名填 $host

Docker 部署

项目根目录包含 Dockerfile,支持容器化部署:

Bash
# 构建镜像
docker build -t youyou-auth .

# 运行容器
docker run -d \
  --name youyou-auth \
  -p 8080:8080 \
  -v $(pwd)/configs:/app/configs \
  youyou-auth
Docker 部署时,确保 MySQL 和 Redis 也在同一网络中,或修改配置文件中的地址为实际地址。

API 概述

客户端 API 统一挂在 /api/v1 路由组下,所有请求默认经过安全中间件处理:

  • 请求参数:使用应用专属 RSA 公钥加密后放在 X-Encrypt 请求头
  • 请求完整性:用 APPKEY 对参数做 MD5 签名(X-Sign),防篡改
  • 防重放:10 位时间戳 + Redis SETNX,5 分钟窗口
  • 响应体:默认返回明文 JSON;可选加密响应(X-Resp-Enc: 1

接口分类

角色 说明 鉴权
🧑 终端用户软件最终使用者用户 Token
👤 应用管理者应用所有者/客服用户 Token
公开/服务无需登录
注意:本文档只覆盖客户端 API(/api/v1)。管理端 API(/api/admin)是后台管理系统使用的,不在本文档范围。

安全机制

所有客户端请求(除两个例外)都必须携带以下安全头:

请求头 必填 说明
X-App-Id应用 ID
X-Timestamp10 位 Unix 秒,与参数中的 time 一致
X-SignMD5(排序拼接参数 + APPKEY),小写十六进制
X-Encryptbase64(RSA_PKCS1v15(应用公钥, JSON(params)))
Authorization🔑Bearer <用户 Token>(需登录的接口)
X-Resp-Enc1 请求加密响应(可选)

两个例外(参数不加密)

接口 原因
GET /api/v1/public-key引导拉取公钥,明文请求、明文返回
POST /api/v1/user/avatar-uploadmultipart 文件上传无法走 RSA 通道

签名算法

签名计算步骤:

  1. 收集业务参数到 params(map,全部为字符串)
  2. 必须包含 time 字段,值等于 X-Timestamp
  3. 忽略 signsign_type 字段
  4. 按 key 升序排序,拼接为 k=v&k=v 格式
  5. 末尾追加 APPKEY(无分隔符)
  6. 取 MD5,结果小写十六进制
Python
import hashlib

def sign_params(params: dict, app_key: str) -> str:
    # 忽略 sign / sign_type
    keys = sorted(k for k in params if k not in ("sign", "sign_type"))
    raw = "&".join(f"{k}={params[k]}" for k in keys) + app_key
    return hashlib.md5(raw.encode()).hexdigest()  # 小写十六进制

快速接入

以下是完整的接入流程,适合开发初学者参考:

第一步:获取应用凭证

登录管理后台,创建应用后系统会自动生成:

  • APP_ID:应用 ID(用于 X-App-Id 请求头)
  • APP_KEY:应用密钥(用于签名,不传输,仅本地参与 MD5 计算)
  • RSA 公钥:用于加密请求体

第二步:拉取公钥

HTTP
GET /api/v1/public-key?app_id=APP1234567890

// 返回明文 JSON(无需加密头)
{
  "code": 0,
  "data": {
    "public_key": "-----BEGIN RSA PUBLIC KEY-----\n..."
  }
}

第三步:构造请求(Python 示例)

Python
import time, json, hashlib, base64, requests
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import serialization

# 配置
APP_ID = "APP1234567890"
APP_KEY = "your_app_key_here"
PUB_PEM = """-----BEGIN RSA PUBLIC KEY-----
<应用专属 RSA 公钥>
-----END RSA PUBLIC KEY-----"""

def load_pubkey(pem):
    return serialization.load_pem_public_key(pem.encode())

def sign_params(params, app_key):
    keys = sorted(k for k in params if k not in ("sign", "sign_type"))
    raw = "&".join(f"{k}={params[k]}" for k in keys) + app_key
    return hashlib.md5(raw.encode()).hexdigest()

def rsa_encrypt(plain_json, pub_pem):
    pub = load_pubkey(pub_pem)
    ct = pub.encrypt(plain_json.encode(), padding.PKCS1v15())
    return base64.b64encode(ct).decode()

def build_headers(params, token=None):
    ts = str(int(time.time()))
    params = dict(params)
    params["time"] = ts  # 必须带 time,且与 X-Timestamp 一致
    sign = sign_params(params, APP_KEY)
    x_encrypt = rsa_encrypt(json.dumps(params), PUB_PEM)
    h = {
        "X-App-Id": APP_ID,
        "X-Timestamp": ts,
        "X-Sign": sign,
        "X-Encrypt": x_encrypt,
        "Content-Type": "application/x-www-form-urlencoded",
    }
    if token:
        h["Authorization"] = f"Bearer {token}"
    return h
关键点:params 必须包含 time 字段,且其值等于 X-Timestamp。否则签名比对会失败,返回 CodeSignError

第四步:发送验证码并注册

Python
# 发送验证码
params = {"email": "user@example.com", "type": "register"}
headers = build_headers(params)
r = requests.post("https://your-host/api/v1/email/send-code", headers=headers)
print(r.json())

# 注册(收到验证码后)
params = {
    "email": "user@example.com",
    "password": "123456",
    "nickname": "测试用户",
    "verify_code": "123456",  # 邮箱收到的验证码
}
headers = build_headers(params)
r = requests.post("https://your-host/api/v1/user/register", headers=headers)
result = r.json()
print(result)
# 成功返回: {"code":0,"msg":"注册成功","data":{"uid":..,"token":..,"refresh_token":..}}

# 保存 token 用于后续请求
USER_TOKEN = result["data"]["token"]

第五步:调用需登录接口

Python
# 查询用户资料
params = {}
headers = build_headers(params, token=USER_TOKEN)
r = requests.get("https://your-host/api/v1/user/profile", headers=headers)
print(r.json())

# 签到
params = {}
headers = build_headers(params, token=USER_TOKEN)
r = requests.post("https://your-host/api/v1/checkin/do", headers=headers)
print(r.json())

用户系统

发送验证码

POST /api/v1/email/send-code
参数 类型 必填 说明
emailstring必填邮箱地址
typestring必填验证码用途:register / reset_password / change_password

用户注册

POST /api/v1/user/register
参数 类型 必填 说明
emailstring必填邮箱地址
passwordstring必填登录密码(≥6 位)
nicknamestring必填用户昵称
verify_codestring必填邮箱验证码

用户登录

POST /api/v1/user/login
参数 类型 必填 说明
emailstring必填邮箱地址
passwordstring必填登录密码
udidstring选填设备唯一标识(建议传,用于多端管理和按设备踢人)
Token 滑动续期:本系统已启用滑动续期,只要客户端保持活动(如定时发心跳),access token 不会自然过期,无需主动刷新。软件关闭后失效则直接重新登录即可。

查询用户资料

GET /api/v1/user/profile

需要登录态(携带有效用户 Token)。

修改密码

POST /api/v1/user/change-password
参数 类型 必填 说明
old_passwordstring必填旧密码
new_passwordstring必填新密码(≥6 位)
verify_codestring必填邮箱验证码

心跳系统

心跳系统用于检测用户是否还在线,防止多开/盗用。客户端应定时上报心跳。

心跳上报

POST /api/v1/heartbeat/report
参数 类型 必填 说明
udidstring必填设备唯一标识
client_verstring选填客户端版本号(用于版本校验提示)

推荐心跳间隔:根据返回的 next_interval 字段定时发送,通常 30-60 秒一次。

心跳状态查询

GET /api/v1/heartbeat/status
参数 类型 必填 说明
udidstring必填设备唯一标识

断开授权

POST /api/v1/heartbeat/disconnect
参数 类型 必填 说明
udidstring必填设备唯一标识

会员系统

查询会员状态

GET /api/v1/member/status

需要登录态。返回当前用户的会员等级和有效期。

会员权限校验

POST /api/v1/member/verify
参数 类型 必填 说明
udidstring选填设备标识(用于踢出检查)
featurestring选填功能标识(门禁判断依据)

服务间会员查询

GET /api/v1/member/query
参数 类型 必填 说明
uiduint必填目标用户 UID

无需用户 Token,用于第三方服务端按 UID 查会员状态。

卡密系统

兑换卡密

POST /api/v1/cardkey/exchange
参数 类型 必填 说明
card_nostring必填卡号

兑换到当前用户。已用/不存在的卡密会报错。

查询卡密信息

GET /api/v1/cardkey/info
参数 类型 必填 说明
card_nostring必填卡号

我的卡密列表

GET /api/v1/cardkey/list
参数 类型 必填 说明
statusint选填状态筛选:0=未使用 1=已使用 2=全部(默认 2)
pageint选填页码(默认 1)
page_sizeint选填每页条数(默认 20)

商店系统

商品列表

GET /api/v1/store/products
参数 类型 必填 说明
pageint选填页码(默认 1)
page_sizeint选填每页条数(默认 20,上限 100)

仅返回上架商品。

购买商品

POST /api/v1/store/purchase
参数 类型 必填 说明
product_iduint必填商品 ID
quantityuint选填购买数量(默认 1)

扣 U 币/库存。余额不足/限购/下架等会返回细分错误码。

签到系统

每日签到

POST /api/v1/checkin/do

无需参数。重复签到会报错 CodeAlreadyCheckin

签到状态

GET /api/v1/checkin/status

返回今日是否已签到。

签到历史

GET /api/v1/checkin/history
参数 类型 必填 说明
pageint选填页码(默认 1)
page_sizeint选填每页条数(默认 20)

U 币充值

U 币充值是「人民币 → U 币」的兑换通道。支持易支付、支付宝、微信。

充值流程

  1. 拉取套餐:GET /charge/packages → 展示套餐
  2. 创建订单:POST /charge/create → 返回支付参数
  3. 拉起支付:按 pay.method 处理(跳转/扫码/调起)
  4. 轮询结果:GET /charge/status → 直到 status=1

创建充值订单

POST /api/v1/charge/create
参数 类型 必填 说明
channelstring必填支付渠道:third_epay / alipay / wechat
package_iduint必填充值套餐 ID
modestring选填拉起方式:redirect(默认) / qrcode / jsapi / app
openidstring选填微信 jsapi 调起时必传

查询充值套餐

GET /api/v1/charge/packages

返回本应用已上架充值套餐列表。

查询订单状态

GET /api/v1/charge/status
参数 类型 必填 说明
order_nostring必填充值订单号
重要:金额单位为「分」!money=3000 表示 ¥30.00。前端展示需 /100 转元。

订单状态枚举

status 含义 客户端表现
0待支付已拉起支付页,轮询 status 等待变为 1
1已支付U 币已到账
2已关闭订单已关闭,不可再支付

错误码

以下是常见错误码及其含义:

错误码 含义 触发位置
CodeInvalidParams参数缺失/非法、RSA 解密失败SecurityMiddleware / handler
CodeExpired时间戳超出窗口(5 分钟)SecurityMiddleware
CodeAppNotFound应用不存在SecurityMiddleware
CodeAppDisabled应用已禁用SecurityMiddleware
CodeSignError签名不匹配SecurityMiddleware
CodeReplayAttack重放攻击(重复请求)SecurityMiddleware
CodeUnauthorizedToken 无效/缺失AuthMiddleware
CodeUserBanned用户被封禁AuthMiddleware
CodeForbidden功能开关关闭(注册/登录)user_handler
CodeAlreadyCheckin重复签到checkin_handler
CodeCardNotFound卡密不存在cardkey_handler
CodeCardUsed卡密已使用cardkey_handler
CodeInsufficientUcoinU 币余额不足store_handler
CodeStockInsufficient库存不足store_handler
CodePurchaseLimit超过限购数量store_handler
排查建议:遇到 CodeSignError 时,检查 params 是否包含 time 字段,且其值与 X-Timestamp 一致。