大数跨境

APP极简Token认证方案

APP极简Token认证方案 wordpress知识
2026-09-27
4

在APP后端开发中,登录鉴权是不可或缺的基础模块。本文分享一套轻量化登录鉴权方案,涵盖登录、鉴权、凭证刷新、退出登录及强制下线等核心功能。

整体设计思路

本方案采用双Token(AccessToken + RefreshToken)机制,生成高熵随机字符串并存储于MySQL数据库中:

  • AccessToken:用于业务接口鉴权,有效期较短,用于访问各类业务接口。

  • RefreshToken:用于刷新凭证,有效期较长。当AccessToken过期时,用于换取全新凭证,避免用户频繁重新输入账号密码。

客户端请求时需在请求头携带Token,后端通过查询数据库校验凭证的有效性与过期状态。在退出登录、修改密码或被管理员强制下线时,直接删除数据库记录即可使登录态立即失效。

请求头规范如下:

Authorization: Bearer {token字符串}

数据库表设计

新建 user_token 表以保存所有客户端登录凭证,并合理设置索引以保障查询效率:

CREATE TABLE `user_token` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  `user_id` int NOT NULL COMMENT '关联用户ID',
  `access_token` varchar(128) NOT NULL COMMENT '访问令牌',
  `refresh_token` varchar(128) NOT NULL COMMENT '刷新令牌',
  `access_expire_at` int NOT NULL COMMENT 'access过期时间戳(秒)',
  `refresh_expire_at` int NOT NULL COMMENT 'refresh过期时间戳(秒)',
  `create_time` int NOT NULL COMMENT '记录创建时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_access_token` (`access_token`),
  UNIQUE KEY `idx_refresh_token` (`refresh_token`),
  KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='APP登录token表';

索引说明:

  • access_token 与 refresh_token 设置唯一索引,用于通过Token快速检索记录。

  • user_id 设置普通索引,便于按用户批量删除记录,实现全设备强制踢下线。

  • 时间字段统一采用时间戳格式,便于后端代码处理。

注意:MySQL不会自动过期删除数据,需配置定时任务清理过期脏数据。

核心代码实现

生成Token工具函数

使用安全随机函数生成64位Token,防猜测性强,满足APP安全需求。

/**
 * 生成64位随机token字符串
 */
function gen_token(): string
{
    return bin2hex(random_bytes(32));
}

登录逻辑实现

账号密码校验通过后,生成一对Token并写入数据库。支持多设备同时登录与单点登录(新设备挤掉旧设备)两种模式。

// 校验账号密码逻辑省略,得到登录用户ID
$userId = 1001;
// 单点登录开启:登录前清除该用户所有旧token记录
Db::name('user_token')->where('user_id', $userId)->delete();

$accessToken = gen_token();
$refreshToken = gen_token();
$now = time();

// access有效期2小时;refresh有效期7天
$accessExpire = $now + 7200;
$refreshExpire = $now + 7 * 86400;

Db::name('user_token')->insert([
    'user_id' => $userId,
    'access_token' => $accessToken,
    'refresh_token' => $refreshToken,
    'access_expire_at' => $accessExpire,
    'refresh_expire_at' => $refreshExpire,
    'create_time' => $now
]);

// 返回给APP客户端
return json([
    'access_token' => $accessToken,
    'refresh_token' => $refreshToken,
    'access_expires_in' => 7200
]);

鉴权中间件

需登录的接口统一通过中间件拦截,校验Token有效性与过期时间。支持开启滑动续期,即用户持续操作时自动延长AccessToken有效期,避免中途掉线。

header('Authorization', '');
if (!str_starts_with($authHeader, 'Bearer ')) {
    return json(['code' => 401, 'msg' => '请先登录'], 401);
}

$accessToken = substr($authHeader, 7);
$now = time();

// 根据token查询,同时校验是否过期
$tokenRow = Db::name('user_token')
    ->where('access_token', $accessToken)
    ->where('access_expire_at', '>', $now)
    ->find();

if (!$tokenRow) {
    return json(['code' => 401, 'msg' => '登录凭证失效,请重新登录'], 401);
}

// 滑动续期,每次访问重置过期时间
Db::name('user_token')
    ->where('access_token', $accessToken)
    ->update(['access_expire_at' => time() + 7200]);

// 将用户ID注入request对象,业务接口直接读取使用
$request->userId = $tokenRow['user_id'];

刷新Token接口

当AccessToken过期时,APP调用刷新接口传入RefreshToken换取新凭证。此环节采用令牌轮换机制,删除旧记录并生成全新的一对Token,提升安全性。接口地址示例:POST /api/token/refresh

$refreshToken = $request->post('refresh_token');
$now = time();

$row = Db::name('user_token')
    ->where('refresh_token', $refreshToken)
    ->where('refresh_expire_at', '>', $now)
    ->find();

if (!$row) {
    return json(['code' => 401, 'msg' => '刷新凭证失效,请重新登录'], 401);
}

// 删除旧的登录记录
Db::name('user_token')->where('id', $row['id'])->delete();

// 生成全新token
$newAccess = gen_token();
$newRefresh = gen_token();

Db::name('user_token')->insert([
    'user_id' => $row['user_id'],
    'access_token' => $newAccess,
    'refresh_token' => $newRefresh,
    'access_expire_at' => time() + 7200,
    'refresh_expire_at' => time() + 7 * 86400,
    'create_time' => time()
]);

return json([
    'access_token' => $newAccess,
    'refresh_token' => $newRefresh,
    'access_expires_in' => 7200
]);

退出与强制下线

直接删除数据表对应记录,登录态即刻失效。

// 用户主动退出,销毁当前设备token
Db::name('user_token')->where('access_token', $accessToken)->delete();

// 管理员操作:让该用户所有设备全部下线
Db::name('user_token')->where('user_id', $userId)->delete();

定时清理过期数据

由于MySQL无Key过期自动回收机制,需配置Crontab定时任务(如每小时执行一次),定期清理已失效的Token记录,防止数据表持续膨胀。

$now = time();
Db::name('user_token')
    ->where('access_expire_at', '<', $now)
    ->where('refresh_expire_at', '<', $now)
    ->delete();

注意事项与优化建议

  • 当前方案每次鉴权均执行SQL查询,适用于中小流量APP。若QPS极高,建议增加Redis等缓存层进行优化。

  • 线上环境务必启用HTTPS,防止Token被抓包泄露。

  • 登录接口需做好IP限流策略,防止账号遭受暴力破解。

#token

【声明】内容源于网络
0
0
wordpress知识
各类跨境出海行业相关资讯
内容 361
粉丝 0
wordpress知识 各类跨境出海行业相关资讯
总阅读10.8k
粉丝0
内容361