我应该如何使用PHP和MySQL(不使用OAuth)以安全的方式对一组Web API实现“基于令牌的身份验证”?

我使用Slim框架在 PHP中开发了一些Web API,移动应用程序(iOS和 Android)使用它来处理他们的请求并获取所需的数据.

最后,在每个API中,我将从移动应用程序收到的请求发送到我网站代码库中的相应功能.然后相应的函数接受请求和请求参数,处理请求并返回所需的数据.然后,API以JSON格式将数据返回到移动应用程序.这是当前的工作流程.

现在,我想根据用户身份验证提供网站资源(即网站代码库和数据中的功能)的可用性.简而言之,我想在这种情况下实现“基于令牌的身份验证”方案.

以下应该是我实现’基于令牌的身份验证’之后的流程:

>当用户第一次通过在对登录API的请求中发送用户名和密码登录系统时,一旦成功验证该特定用户的用户名和密码组合,就会生成一个安全令牌.此安全令牌也将与用户名/密码/某些散列值一起存储到某些MySQL数据库表中,以识别用户进一步处理.如果验证失败,则不应生成安全令牌,用户也不应该登录.
>成功登录后,生成的安全令牌将在登录API成功响应时发送回用户.现在,直到用户使用每个后续请求登录,此令牌将被发送到相关API,并最终将其发送到身份验证功能以验证其有效性.
>如果任何请求发送了无效令牌,则应发送“请先登录”消息作为响应,并且网站资源不应该被访问.
>用户注销后,应从数据库中删除此安全令牌条目,或者应对其执行任何适当的操作.

从那以后,我在职业生涯中第一次开始“基于令牌的身份验证”,我的上述方法可能会出错.如果我做错了什么,请纠正我的错误.

我找到了以下链接,但那些我没有找到有用的链接,因为它们缺少一步一步描述的工作代码示例:

PHP HMAC Restful API that uses Phalcon Micro framework

PEAR package for JWT

如果您可以提供包含数据库表创建,PHP和MySQL之间的连接,然后创建安全令牌,检查当前登录用户的安全令牌的有效性等的整个代码,那对我来说真的很棒.

此外,如果您可以为上述两个(或两个)选项中的任何一个提供工作代码示例作为此问题的答案,这也将是非常好的.如果除了我提供的完整工作代码示例之外还有其他选项,欢迎您提出答案.

N.B.:-请不要建议我使用OAuth身份验证过程.

以下是我自己尝试的代码,但我不知道它是对还是错.我的方法是正确还是错误?

要创建令牌,我使用此函数作为参数,即用户的数据

define('SECRET_KEY',"fakesecretkey");

function createToken($data)
{
    /* Create a part of token using secretKey and other stuff */
    $tokenGeneric = SECRET_KEY.$_SERVER["SERVER_NAME"]; // It can be 'stronger' of course

    /* Encoding token */
    $token = hash('sha256',$tokenGeneric.$data);

    return array('token' => $token,'userData' => $data);
}

因此,用户可以对自己进行身份验证并接收包含令牌(genericPart,他的数据,已编码)和未编码的数据的数组:

function auth($login,$password)
{
    // we check user. For instance,it's ok,and we get his ID and his role.
    $userID = 1;
    $userRole = "admin";

    // Concatenating data with TIME
    $data = time()."_".$userID."-".$userRole;
    $token = createToken($data);
    echo json_encode($token);
}

然后用户可以将他的令牌发送给我未编码的数据,以便检查:

define('VALIDITY_TIME',3600);

function checkToken($receivedToken,$receivedData)
{
    /* Recreate the generic part of token using secretKey and other stuff */
    $tokenGeneric = SECRET_KEY.$_SERVER["SERVER_NAME"];

    // We create a token which should match
    $token = hash('sha256',$tokenGeneric.$receivedData);   

    // We check if token is ok !
    if ($receivedToken != $token)
    {
        echo 'wrong Token !';
        return false;
    }

    list($tokenDate,$userData) = explode("_",$receivedData);
    // here we compare tokenDate with current time using VALIDITY_TIME to check if the token is expired
    // if token expired we return false

    // otherwise it's ok and we return a new token
    return createToken(time()."#".$userData);   
}

$check = checkToken($_GET['token'],$_GET['data']);
if ($check !== false)
    echo json_encode(array("secureData" => "Oo")); // And we add the new token for the next request

我对吗?

解决方法

根据我们的讨论,您可以执行类似于OAuth2.0的操作.我建议实现完整规范,但由于它是您的应用程序,您可以进行更改.

这是一张RFC 6750的图表

+--------+                               +---------------+
 |        |--(A)- Authorization Request ->|   Resource    |
 |        |                               |     Owner     |
 |        |<-(B)-- Authorization Grant ---|               |
 |        |                               +---------------+
 |        |
 |        |                               +---------------+
 |        |--(C)-- Authorization Grant -->| Authorization |
 | Client |                               |     Server    |
 |        |<-(D)----- Access Token -------|  (Slim API)   |
 |        |                               +---------------+
 |        |
 |        |                               +---------------+
 |        |--(E)----- Access Token ------>|    Resource   |
 |        |                               |     Server    |
 |        |<-(F)--- Protected Resource ---|               |
 +--------+                               +---------------+

在苗条,你可以有三个端点:

POST用户名/密码:

/的OAuth / V1 /认证/

返回{token:foo}

GET,其中{token}是您的唯一令牌

/的OAuth / V1 /令牌/ {令牌}

返回{username:joe,permissions [‘page:admin’,’users:full’],expires:123456}

DELETE传递{token}

/的OAuth / V1 /令牌/撤消

回复200 OK和空身.

现在,它是如何工作的:

>当他们进行身份验证时,只需返回带有令牌的JSON对象,客户端将其存储在cookie之类的内容中.
>客户端将此文件传递到资源服务器中,如RFC section 2.1中所标识的那样(在数据库/ nosql / whatever中查找用户权限):

GET /resource HTTP/1.1

06001

您的资源服务器与后端的Slim API联系以确定您的权限.然后,服务器决定您可以看到的内容.

如果您不喜欢将其作为标题发送,请参阅section 2.2,它描述了如何在正文中发送它,或者section 2.3将其作为URI查询发送.

这些显然不需要是不同的服务器.你可以按照自己的意愿实现它.

相关文章

文章浏览阅读8.4k次,点赞8次,收藏7次。SourceCodester Onl...
文章浏览阅读3.4k次,点赞46次,收藏51次。本文为大家介绍在...
文章浏览阅读1.1k次。- php是最优秀, 最原生的模板语言, 替代...
文章浏览阅读1.1k次,点赞18次,收藏15次。整理K8s网络相关笔...
文章浏览阅读1.2k次,点赞22次,收藏19次。此网络模型提供了...
文章浏览阅读1.1k次,点赞14次,收藏19次。当我们谈论网络安...