关闭。这个问题是opinion-based .它目前不接受答案。
想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文回答问题.
3年前关闭。
Improve this question
我正在向旧版 PHP 站点添加 REST API。这是为内部应用程序提供一个端点,所以我在如何设计事物以及支持和不支持的方面非常自由。
我现在需要添加到此 API 的是一种登录方式,然后以特定用户身份执行操作。该网站是多年前建立的,不一定采用当时的最佳实践,因此不幸的是,我在如何做到这一点方面受到了一些限制。所有这些都需要在 PHP 5.4 和 MySQL 5.6 中运行。
我一直在阅读有关此的常见设计,OAuth1/2 看起来是最常见的标准。但是,对于我的目的来说,这似乎是一种过度杀伤,因为它具有我不需要的各种功能,而且实现起来似乎非常复杂。
相反,我打算做这样的事情:
get_session
API 端点会生成随机 session ID,将其保存到数据库中的表中并将其返回给客户端。 login
发送请求来进行身份验证。端点,发送用户名、密码和 session ID(显然是通过 HTTPS)。 logout
发送请求端点和服务器删除与用户帐户的关联。 这是一个合理的设计吗?它显然不是很复杂,但我正在寻找可以在没有巨大麻烦或不需要第三方库的情况下实现的东西。
最佳答案
REST 作为一个概念的主要观点之一是避免使用 session 状态,以便更轻松地水平扩展 REST 端点的资源。如果您打算使用 PHP 的 $_SESSION
如您的问题中所述,您会发现自己处于一个困难的境地,在您想要扩展的情况下必须实现共享 session 存储。
虽然 OAuth 将是您想要执行的操作的首选方法,但完整的实现可能比您想投入的工作要多。但是,您可以制定一些半措施,并且仍然保持无 session 。您以前甚至可能见过类似的解决方案。
通过这种方式,您可以保持“无 session ”REST 的理想状态,而且您在交换的任何部分都不会真正传输 Secret。
客户端示例:
$token = "Bmn0c8rQDJoGTibk"; // base64_encode(random_bytes(12));
$secret = "yXWczx0LwgKInpMFfgh0gCYCA8EKbOnw"; // base64_encode(random_bytes(24));
$stamp = "2017-10-12T23:54:50+00:00"; // date("c");
$sig = hash_hmac('SHA256', $stamp, base64_decode($secret));
// Result: "1f3ff7b1165b36a18dd9d4c32a733b15c22f63f34283df7bd7de65a690cc6f21"
$request->addHeader("X-Auth-Token: $token");
$request->addHeader("X-Auth-Signature: $sig");
$request->addHeader("X-Auth-Timestamp: $stamp");
服务器示例:
$token = $request->getToken();
$secret = $auth->getSecret($token);
$sig = $request->getSignature();
$success = $auth->validateSignature($sig, $secret);
值得注意的是,如果决定使用时间戳作为随机数,您应该只接受最近几分钟内生成的时间戳,以防止重放攻击。大多数其他身份验证方案将在签名数据中包含其他组件,例如资源路径、 header 数据的子集等,以进一步锁定签名以仅适用于单个请求。
2020 编辑:这基本上就是 JSON Web Tokens [JWT]是。
当这个答案最初是在 2013 年编写时,JWT 还很新,[而且我没有听说过它们],但到 2020 年,它们已经牢固地确立了它们的实用性。下面是一个手动实现的例子来说明它们的简单性,但是有大量的库可以为您进行编码/解码/验证,可能已经融入您选择的框架中。
function base64url_encode($data) {
$b64 = base64_encode($data);
if ($b64 === false) {
return false;
}
$url = strtr($b64, '+/', '-_');
return rtrim($url, '=');
}
$token = "Bmn0c8rQDJoGTibk"; // base64_encode(random_bytes(12));
$secret = "yXWczx0LwgKInpMFfgh0gCYCA8EKbOnw"; // base64_encode(random_bytes(24));
// RFC-defined structure
$header = [
"alg" => "HS256",
"typ" => "JWT"
];
// whatever you want
$payload = [
"token" => $token,
"stamp" => "2020-01-02T22:00:00+00:00" // date("c")
];
$jwt = sprintf(
"%s.%s",
base64url_encode(json_encode($header)),
base64url_encode(json_encode($payload))
);
$jwt = sprintf(
"%s.%s",
$jwt,
base64url_encode(hash_hmac('SHA256', $jwt, base64_decode($secret), true))
);
var_dump($jwt);
产量:
string(167) "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbiI6IkJtbjBjOHJRREpvR1RpYmsiLCJzdGFtcCI6IjIwMjAtMDEtMDJUMjI6MDA6MDArMDA6MDAifQ.8kvuFR5xgvaTlOAzsshymHsJ9eRBVe-RE5qk1an_M_w"
并且可以是validated by anyone符合标准,这是非常受欢迎的atm。
无论如何,大多数 API 将它们添加到 header 中:
$request->addHeader("Authorization: Bearer $jwt");
关于php - 为 PHP REST API 实现简单的身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46719676/