本文目录导读:

- 核心数据模型:用户 (User)
- 会话 (Session) 数据结构
- API 令牌 (Token) 数据结构
- OAuth 2.0 / 第三方登录数据结构
- 密码重置数据结构
- 角色与权限 (RBAC) 数据结构
- 安全实践建议
针对PHP项目的“认证数据结构”(Authentication Data Structure, ADS),通常指的是用于存储和处理用户身份验证信息的数据模型、令牌结构以及数据库表结构。
以下是针对PHP项目(特别是现代框架如Laravel、Symfony,或纯PHP项目)的一套推荐的、健壮的认证数据结构设计指南。
核心数据模型:用户 (User)
这是认证的基础,绝大多数PHP框架默认使用users表。
数据库表结构 (users):
| 字段名 | 类型 | 约束 | 描述 |
|---|---|---|---|
id |
BIGINT UNSIGNED |
PK, AUTO_INCREMENT | 用户唯一标识 |
name / username |
VARCHAR(255) |
NOT NULL, UNIQUE | 用户名或显示名称 |
email |
VARCHAR(255) |
NOT NULL, UNIQUE | 邮箱(常用于登录验证) |
password |
VARCHAR(255) |
NOT NULL | 哈希后的密码(必用password_hash()) |
remember_token |
VARCHAR(100) |
NULLABLE | “记住我”功能令牌(Laravel风格) |
email_verified_at |
TIMESTAMP |
NULLABLE | 邮箱验证时间 |
status |
ENUM('active','inactive','banned') |
NOT NULL, DEFAULT 'active' | 账号状态 |
last_login_at |
TIMESTAMP |
NULLABLE | 最后登录时间 |
last_login_ip |
VARCHAR(45) |
NULLABLE | 最后登录IP |
created_at |
TIMESTAMP |
DEFAULT CURRENT_TIMESTAMP | 创建时间 |
updated_at |
TIMESTAMP |
DEFAULT CURRENT_TIMESTAMP ON UPDATE | 更新时间 |
PHP 代码示例 (Password Hashing):
// 注册时
$hashedPassword = password_hash($_POST['password'], PASSWORD_BCRYPT, ['cost' => 12]);
// 验证时
if (password_verify($inputPassword, $storedHash)) {
// 登录成功
}
会话 (Session) 数据结构
用于传统 Cookie + Session 认证机制。
数据库表 (sessions):
| 字段名 | 类型 | 约束 | 描述 |
|---|---|---|---|
id |
VARCHAR(128) |
PK | 唯一的Session ID |
user_id |
BIGINT UNSIGNED |
NULLABLE, INDEX | 关联的用户ID(游客为空) |
ip_address |
VARCHAR(45) |
NULLABLE | 发起会话的IP |
user_agent |
TEXT |
NULLABLE | 浏览器UA |
payload |
TEXT |
NOT NULL | 序列化的Session数据 |
last_activity |
INT |
NOT NULL, INDEX | 最后活跃时间戳 |
注意: 高并发下,Session存储在数据库会有性能瓶颈,建议使用 Redis 或 Memcached 作为后端存储。
API 令牌 (Token) 数据结构
适用于 RESTful API 或 SPA 应用的无状态认证。
个人访问令牌 (Personal Access Token) - 常用于 Laravel Sanctum
| 字段名 | 类型 | 约束 | 描述 |
|---|---|---|---|
id |
BIGINT UNSIGNED |
PK | 令牌ID |
tokenable_id |
BIGINT UNSIGNED |
NOT NULL, INDEX | 关联用户ID |
tokenable_type |
VARCHAR(255) |
NOT NULL | 模型类(如App\Models\User) |
name |
VARCHAR(255) |
NOT NULL | 令牌名称(给用户看的) |
token |
VARCHAR(64) |
UNIQUE | SHA-256哈希后的令牌 |
abilities |
TEXT |
NULLABLE | 权限列表(JSON格式) |
last_used_at |
TIMESTAMP |
NULLABLE | 最后使用时间 |
expires_at |
TIMESTAMP |
NULLABLE | 过期时间 |
created_at |
TIMESTAMP |
DEFAULT CURRENT_TIMESTAMP | 创建时间 |
updated_at |
TIMESTAMP |
DEFAULT CURRENT_TIMESTAMP ON UPDATE | 更新时间 |
JWT (JSON Web Token) 结构
JWT本身是自包含的,服务端不需要存储Token记录,但需要维护一个黑名单用于登出或废止。
JWT Payload 推荐结构:
{
"iss": "your-app.com", // 签发者
"sub": "1234567890", // 用户ID (Subject)
"iat": 1516239022, // 签发时间
"exp": 1516242622, // 过期时间 (必填)
"jti": "unique-token-id", // Token唯一ID (用于黑名单)
"roles": ["admin", "editor"], // 用户角色 (非标准字段)
"context": {
"tenant_id": "abc", // 多租户上下文 (可选)
"device": "mobile" // 设备类型 (可选)
}
}
JWT 黑名单表 (jwt_blacklist):
| 字段名 | 类型 | 约束 | 描述 |
|---|---|---|---|
id |
BIGINT UNSIGNED |
PK | |
jti |
VARCHAR(255) |
NOT NULL, UNIQUE | JWT的jti声明 |
user_id |
BIGINT UNSIGNED |
NOT NULL, INDEX | 关联用户 |
invalidated_at |
TIMESTAMP |
DEFAULT CURRENT_TIMESTAMP | 加入黑名单时间 |
expires_at |
TIMESTAMP |
NOT NULL | JWT原过期时间(用于清除过期记录) |
OAuth 2.0 / 第三方登录数据结构
如果你的项目支持“通过GitHub/微信/Google登录”:
表 oauth_providers (或 social_accounts):
| 字段名 | 类型 | 约束 | 描述 |
|---|---|---|---|
id |
BIGINT UNSIGNED |
PK | |
user_id |
BIGINT UNSIGNED |
NOT NULL, FOREIGN KEY | 关联本地用户 |
provider |
VARCHAR(50) |
NOT NULL | 平台名 (github, wechat) |
provider_user_id |
VARCHAR(255) |
NOT NULL | 第三方平台的用户ID |
access_token |
TEXT |
NULLABLE | 加密存储的Access Token |
refresh_token |
TEXT |
NULLABLE | 加密存储的Refresh Token |
token_expires_at |
TIMESTAMP |
NULLABLE | Token过期时间 |
created_at |
TIMESTAMP |
DEFAULT CURRENT_TIMESTAMP | 绑定时间 |
唯一索引: UNIQUE KEY on (provider, provider_user_id)
密码重置数据结构
表 password_resets:
| 字段名 | 类型 | 约束 | 描述 |
|---|---|---|---|
email |
VARCHAR(255) |
NOT NULL, INDEX | 用户邮箱 |
token |
VARCHAR(255) |
NOT NULL | 重置令牌(哈希后存储) |
created_at |
TIMESTAMP |
DEFAULT CURRENT_TIMESTAMP | 创建时间 |
安全建议: Token应设置有效期(通常60分钟),并限制单邮箱请求频率。
角色与权限 (RBAC) 数据结构
表 roles:定义角色(如 admin, editor, subscriber)
表 permissions:定义权限(如 create_post, delete_user)
表 role_user:用户与角色关联
表 permission_role:角色与权限关联
| 表名 | 关键字段 | 说明 |
|---|---|---|
roles |
id, name, guard_name |
guard_name 用于区分Web和API |
permissions |
id, name, guard_name |
权限标识 |
model_has_roles |
role_id, model_type, model_id |
多态关联用户 |
model_has_permissions |
permission_id, model_type, model_id |
直接赋予用户的权限 |
安全实践建议
- 绝不存储明文密码:使用
password_hash()+PASSWORD_BCRYPT或PASSWORD_ARGON2ID。 - 令牌存储:
- JWT 令牌通常存储在客户端(LocalStorage 或 Cookie)。
- 不透明的随机令牌(Sanctum/Passport)需要在服务端哈希后存储。
- 数据脱敏:返回给前端的用户信息中,绝不包含
password、remember_token、原始access_token。 - 索引策略:所有用于查询的字段(如
email,provider_user_id,token)必须建立索引。 - 审计日志:对于敏感操作(登录、改密、授权),建议增加
authentication_log表记录时间、IP、UA和结果。
根据项目复杂度,选择合适的数据结构:
- 简单项目:只需要
users表 +sessions表。 - 纯API项目:
users+personal_access_tokens(Sanctum) 或 JWT (需要黑名单表)。 - 多角色复杂系统:在上述基础上增加 RBAC 四表结构。
- 社交登录:务必实现
oauth_providers表。