Code前端首页关于Code前端联系我们

令牌的使用是关于在 PHP

terry 2年前 (2023-09-25) 阅读数 47 #后端开发

1 中使用 JWT。使用令牌

在许多计算机系统中,用户身份验证步骤是必不可少的。最常见的身份验证是帐户和密码身份验证,这是一个注册和登录过程。 。

在现实生活中,人们也需要身份验证。每个人都应该有身份证。想想这张身份证是从哪里来的?办过身份证的人应该都知道,一般到户口簿公安局(不知道是不是)现在改变了?)。工作人员将核实相关信息并确认其准确性。您将获得一张身份证,有效期通常为10-20年。当需要认证时,您可以携带身份证验证来验证您的身份,例如购买火车时。机票、出境或申请其他文件。

在许多在线系统中,令牌类似于身份证。账户密码就相当于我们的账本和我们自己。我们需要检查账户密码并找回。获得token后,我们就可以使用一些需要认证的服务,而且token也是有有效期的。与身份证一样,令牌理论上应该是唯一的。

2。常见的在线认证方法

1. HTTP Basic Auth

这种方式在一些早期的Web系统中比较常见。这种类型会在浏览器中显示一个窗口,您可以在其中输入帐户和密码。这很简单。它很容易使用,但有一个缺点:不安全。账户密码实际上是以明文形式(base64encode)传输的,每次都必须携带。此外,它太丑了。 。 。 Token的用途谈PHP里面JWT的使用

2.Cookies\Session

这种认证方式其实和我们一开始提到的身份证类似。您只需输入一次帐户密码。当认证成功后,系统会将用户信息保存在会话中,会话是服务器的本地存储功能,然后系统会生成唯一的会话id基于session并以cookie的形式发送到浏览器。

cookies 是本地浏览器存储。这个机制的作用就是存储sessionid。您也可以在不使用 cookie 的情况下保存它。早期,一些网站在不支持cookie的浏览器中添加了sessionid。在网址。

cookie中存储的Session ID实际上相当于一个ID号。每次访问网站时我们都会携带此号码。服务器可以使用该号码来查找相应会话中存储的信息。一般情况下,里面会保存一些用户。 uid等信息。 Token的用途谈PHP里面JWT的使用

说实话,这个机制并不是什么大问题,而且大部分时间都有效。然而,cookie 的一个问题是它们不能跨域。很多大公司都有很多网站,这些网站的域名可能不同。此外,当前的移动应用程序对cookie的支持不太好,cookie本身也不支持。最后,会话的服务器存储也需要一些开销,特别是在有很多用户的情况下。还有其他缺点,我不会在这里列出,因为已经写了很多关于它们的文章。

其实我想说这个机制在大多数情况下已经足够了,尤其是对于一些中小型网站。它易于使用并且可以快速开发。

3.JWT

当我们谈论JWT时,它通常会被称为令牌。我的理解是令牌实际上是一个字符串。它可以是 jwt 令牌或 sessionid 令牌。令牌是携带身份验证信息的字符串。细绳。

网上有很多关于JWT部署的文章,而且都很相似。我们懒得在这里重复了。我将发布一个大师教程。我认为这是一个非常清晰的 JSON Web 令牌介绍教程。

简单来说,JWT 基本上是一个解决方案标准。该解决方案中的下一个令牌应由 3 部分组成:Header、Payload、Signature,其中前两部分几乎是纯文本。这是一个 json 对象,它保存一些信息并使用 base64urlencode 编码为字符串。最后一个Signature是用secret加密前两个元素的结果。默认加密算法是SHA256,这个秘密必须只有服务器知道并且需要解密。

最终生成的token是一个比较长的字符串。用户成功登录后,可以将该字符串返回给浏​​览器。浏览器只需在下次发出请求时携带此字符串即可。问题是怎么带呢?许多文章都讨论了插入cookie。按理来说,放入cookies和sessionid有什么区别呢?标准方法是将其放在 HTTP 请求标头的授权字段中。

服务器拿到这个字符串,首先使用base64urldecode解码前两段中的header和payload,然后使用刚才使用的加密算法和secret来验证它们是否与第三段中的签名匹配。如果不同,则说明该token是假的。如果它们相同,则可以信任负载中的信息。一般情况下,Payload会存储一些用户信息,比如uid。如果Payload需要存储一些敏感数据,例如手机号码,建议这样做。首先加密有效负载。

PHP 实践

下面我用 PHP 来做一个简单的例子:

JWT 课程:

<?php

namespace App;

class Jwt
{
    private $alg = 'sha256';

    private $secret = "123456";

    /**
     * alg属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);typ属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT
     */
    public function getHeader()
    {
        $header = [
            'alg' => $this->alg,
            'typ' => 'JWT'
        ];

        return $this->base64urlEncode(json_encode($header, JSON_UNESCAPED_UNICODE));
    }

    /**
     * Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。JWT 规定了7个官方字段,供选用,这里可以存放私有信息,比如uid
     * @param $uid int 用户id
     * @return mixed
     */
    public function getPayload($uid)
    {
        $payload = [
            'iss' => 'admin', //签发人
            'exp' => time() + 600, //过期时间
            'sub' => 'test', //主题
            'aud' => 'every', //受众
            'nbf' => time(), //生效时间
            'iat' => time(), //签发时间
            'jti' => 10001, //编号
            'uid' => $uid, //私有信息,uid
        ];

        return $this->base64urlEncode(json_encode($payload, JSON_UNESCAPED_UNICODE));
    }

    /**
     * 生成token,假设现在payload里面只存一个uid
     * @param $uid int
     * @return string
     */
    public function genToken($uid)
    {
        $header  = $this->getHeader();
        $payload = $this->getPayload($uid);

        $raw   = $header . '.' . $payload;
        $token = $raw . '.' . hash_hmac($this->alg, $raw, $this->secret);

        return $token;
    }


    /**
     * 解密校验token,成功的话返回uid
     * @param $token
     * @return mixed
     */
    public function verifyToken($token)
    {
        if (!$token) {
            return false;
        }
        $tokenArr = explode('.', $token);
        if (count($tokenArr) != 3) {
            return false;
        }
        $header    = $tokenArr[0];
        $payload   = $tokenArr[1];
        $signature = $tokenArr[2];

        $payloadArr = json_decode($this->base64urlDecode($payload), true);

        if (!$payloadArr) {
            return false;
        }

        //已过期
        if (isset($payloadArr['exp']) && $payloadArr['exp'] < time()) {
            return false;
        }

        $expected = hash_hmac($this->alg, $header . '.' . $payload, $this->secret);

        //签名不对
        if ($expected !== $signature) {
            return false;
        }

        return $payloadArr['uid'];
    }

    /**
     * 安全的base64 url编码
     * @param $data
     * @return string
     */
    private function base64urlEncode($data)
    {
        return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
    }

    /**
     * 安全的base64 url解码
     * @param $data
     * @return bool|string
     */
    private function base64urlDecode($data)
    {
        return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
    }
}
复制代码

测试:

<?php
$jwt = new \App\Jwt();

//获取token
$token = $jwt->genToken(1);

//解密token
$uid = $jwt->verifyToken($token);

var_dump($uid);
复制代码

以上代码仅供参考。实际使用时,最好找一个现成的库。重新发明轮子是不可取的。 jwt 的思想是通用的,与语言无关。 github上有很多。 。 。这是 PHP 库:firebase/php-jwt。

最后说一下session和jwt的选择。如果你在网上搜索一下,你可以看到很多文章比较两者的优缺点。最重要的是,每个人都有其优点和缺点。事实上,很多公司既不是seja,也不是jwt,也许它们是。自己创建一个字符串,例如 jwt 令牌,如果该字符串可以代表用户,则将其插入到 cookie 中。

作者:wangbjun
链接:https://juejin.im/post/5c358f116fb9a049eb3c1dd5
来源:掘金
版权归作者所有。商业转载请联系作者获得许可。非商业转载请注明来源。

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门