
本文详解如何使用 jwt(json web token)为 php 后端 api 添加身份认证与授权机制,确保仅允许合法、未被篡改的 android 原生应用发起请求(如新增图书),拒绝 postman 等外部工具或逆向工程客户端的非法访问。
本文详解如何使用 jwt(json web token)为 php 后端 api 添加身份认证与授权机制,确保仅允许合法、未被篡改的 android 原生应用发起请求(如新增图书),拒绝 postman 等外部工具或逆向工程客户端的非法访问。
在移动应用与后端 API 的交互中,“仅限本 App 调用”这一需求无法通过客户端标识(如 User-Agent、包名校验)真正实现——这些信息极易伪造。真正的安全防线在于基于令牌的身份认证与可信上下文验证。JWT 正是这一场景的理想选择:它将用户身份、权限、有效期等关键信息加密签名后交由客户端携带,服务端无需查库即可高效、可信地完成校验。
✅ 正确的安全逻辑流程
- 首次登录认证:Android App 向 /login.php 提交用户名密码(建议 HTTPS + 加密传输);
- 颁发 JWT:服务端验证凭据后,生成含 user_id、role(如 “admin”: true)、exp(过期时间)等声明的 JWT,并返回给 App;
- 后续受保护接口调用:App 在请求头(如 Authorization: Bearer <token>)中携带该 JWT;
- 服务端验证:addNewBook.php 解析并校验 JWT 的签名有效性、时效性及权限声明,仅当全部通过才执行数据库操作。
⚠️ 注意:JWT 本身不防止逆向工程,但能有效阻止“未授权调用”。若需进一步防篡改(如检测是否为正版 APK),需结合 Android 端签名验证(如 PackageManager 校验 SHA-256 签名)+ 服务端白名单校验(非本文重点,但生产环境强烈建议叠加)。
? 示例:JWT 生成与验证(纯原生 PHP,无第三方依赖)
以下代码基于 RFC 7519 实现轻量级 JWT 签发与校验,适用于入门理解与小规模项目:
// 工具函数:Base64Url 安全编码
function base64url_encode($data) {
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
// 生成 JWT(登录成功后调用)
function generate_jwt($payload, $secret = 'your-super-secret-key-256bit') {
$headers = ['alg' => 'HS256', 'typ' => 'JWT'];
$headers_encoded = base64url_encode(json_encode($headers));
$payload_encoded = base64url_encode(json_encode($payload));
$signature = hash_hmac('sha256', "$headers_encoded.$payload_encoded", $secret, true);
$signature_encoded = base64url_encode($signature);
return "$headers_encoded.$payload_encoded.$signature_encoded";
}
// 验证 JWT(在 addNewBook.php 中调用)
function validate_jwt($jwt, $secret = 'your-super-secret-key-256bit') {
$parts = explode('.', $jwt);
if (count($parts) !== 3) return false;
list($header_b64, $payload_b64, $sig_b64) = $parts;
// 解码并解析 payload
$payload = json_decode(base64_decode($payload_b64), true);
if (!$payload || !isset($payload['exp']) || !isset($payload['admin'])) return false;
// 检查过期
if ($payload['exp'] < time()) return false;
// 重新计算签名并比对
$expected_sig = base64url_encode(
hash_hmac('sha256', "$header_b64.$payload_b64", $secret, true)
);
return hash_equals($expected_sig, $sig_b64); // 防时序攻击
}
?️ 改造 addNewBook.php:集成 JWT 验证
<?php
header('Content-Type: application/json; charset=utf-8');
// 1. 数据库连接(务必使用 PDO 或 mysqli 预处理语句!此处仅为流程示意)
$connection = new mysqli("host", "user", "pass", "db");
$connection->set_charset("utf8mb4");
// 2. 提取并验证 JWT
$auth_header = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
if (strpos($auth_header, 'Bearer ') !== 0) {
http_response_code(401);
echo json_encode(['error' => 'Missing or invalid Authorization header']);
exit;
}
$token = trim(substr($auth_header, 7));
if (!validate_jwt($token)) {
http_response_code(401);
echo json_encode(['error' => 'Invalid or expired token']);
exit;
}
// 3. 解析 payload 获取权限(可扩展为角色 RBAC)
$payload = json_decode(base64_decode(explode('.', $token)[1]), true);
if (!$payload['admin']) { // 仅管理员可添加图书
http_response_code(403);
echo json_encode(['error' => 'Insufficient permissions']);
exit;
}
// 4. 安全处理输入(关键!防止 SQL 注入)
$bookName = $connection->real_escape_string($_POST['bookName'] ?? '');
if (empty($bookName)) {
http_response_code(400);
echo json_encode(['error' => 'Book name is required']);
exit;
}
// 5. 执行插入(推荐改用预处理语句)
$stmt = $connection->prepare("INSERT INTO BOOKS (NAME) VALUES (?)");
$stmt->bind_param("s", $bookName);
$stmt->execute();
echo json_encode(['success' => true, 'id' => $stmt->insert_id]);
?>
? 关键注意事项与最佳实践
- 密钥安全:$secret 必须足够长(建议 32 字节以上随机字符串)、严格保密,绝不可硬编码在 Git 中,应通过环境变量或配置文件隔离;
- HTTPS 强制启用:JWT 在传输中明文可见(Header.Payload 可解码),必须全程使用 HTTPS,否则密钥与令牌易被劫持;
- 避免敏感信息泄露:Payload 中不要存放密码、密钥、银行卡号等,仅放必要标识与权限;
- Token 生命周期:设置合理 exp(如 1 小时),搭配 Refresh Token 机制提升体验与安全性;
- SQL 注入防护:示例中已用 real_escape_string,但强烈推荐改用预处理语句(mysqli::prepare),这是防御注入的黄金标准;
- Android 端配合:App 需安全存储 JWT(如 Android Keystore),并在每次请求中正确设置 Authorization 头。
通过以上方案,你的 addNewBook.php 将只响应持有有效、未过期且具备 admin:true 声明的 JWT 请求——Postman 若无合法令牌则直接被拒,而正版 App 在登录后即可顺畅调用。这才是面向生产环境的、可落地的 API 安全基石。
立即学习“PHP免费学习笔记(深入)”;
文章来自机圈观察员网,发布者:,转载请注明出处:https://www.jqgcy.com/jiquanzatan/123889.html