PHP 实现JWT认证

in php

使用PHP实现JWT认证

JSON Web Token(JWT)是一种用于在网络应用间传递身份认证信息的开放标准。它由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。在本篇博客中,我们将介绍如何在PHP应用程序中使用JWT进行身份认证。

1. 安装依赖库

首先,我们需要使用Composer来管理我们的依赖库。在项目根目录下创建一个composer.json文件,并添加以下内容:

{
  "require": {
    "firebase/php-jwt": "^5.4"
  }
}

然后在命令行终端中运行以下命令安装依赖库:

composer install

2. 生成JWT

在PHP应用程序中生成JWT需要使用firebase/php-jwt库。以下是一个生成JWT的示例:

<?php
require 'vendor/autoload.php';

use Firebase\JWT\JWT;

$key = 'your_secret_key';
$payload = array(
    "user_id" => 1,
    "username" => "john.doe"
);

$jwt = JWT::encode($payload, $key, 'HS256');

echo "Generated JWT: " . $jwt;
?>

在上述示例中,我们使用JWT::encode()方法生成JWT。需要提供载荷(即数据)和一个秘钥来签名JWT。生成的JWT将在终端输出。

3. 验证JWT

在PHP应用程序中验证JWT需要使用相同的firebase/php-jwt库。以下是一个验证JWT的示例:

<?php
require 'vendor/autoload.php';

use Firebase\JWT\JWT;

$key = 'your_secret_key';
$jwt = 'your_generated_jwt';

try {
    $decoded = JWT::decode($jwt, $key, array('HS256'));
    $user_id = $decoded->user_id;
    $username = $decoded->username;

    echo "User ID: " . $user_id . "\n";
    echo "Username: " . $username . "\n";
} catch (Exception $e) {
    echo 'Invalid JWT: ' . $e->getMessage();
}
?>

在上述示例中,我们使用JWT::decode()方法验证JWT的有效性并解码其中的数据。如果JWT有效,则输出包含用户ID和用户名的信息。否则,将输出无效JWT的错误消息。

参考文献

结论

在本篇博客中,我们介绍了如何在PHP应用程序中使用JWT进行身份认证。通过使用firebase/php-jwt库,我们可以方便地生成和验证JWT。JWT提供了一种安全可靠的方式来传递身份认证信息,并在网络应用程序之间实现无状态认证。

请记住,在实际应用中,确保妥善保管JWT的秘钥,并采取其他安全措施(如HTTPS)来保护JWT的传输和使用。

如果您想使用PHP对接 一个第三方 xxx ,以下是一个示例代码片段,展示了如何使用PHP中的base64_encodehash函数与xxx进行对接:

这家平台对接 对于 openssl 有要求 不能对于1.0.2, 我的服务器环境 亚马逊Centos 需要编译安装.

// 输入数据
$data = '<compact json here>';

// 计算SHA-512散列
$digest = hash('sha512', $data, true);

// 进行base64编码
$base64 = base64_encode($digest);

// 替换base64编码中的字符
$base64url = str_replace(['+', '/', '='], ['-', '_', ''], $base64);

// 发送请求到xxx的API
$url = 'https://xxx.example.com/api/encrypt';
$params = [
    'data' => $base64url,
];

// 使用cURL发送POST请求
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

// 处理xxx的响应
if ($response !== false) {
    // 对响应进行处理...
} else {
    // 请求失败处理...
}

这个示例代码中,首先使用hash函数计算输入数据的SHA-512散列。然后,使用base64_encode对散列结果进行base64编码。接下来,使用str_replace函数替换base64编码中的字符,以生成URL安全的编码结果。最后,使用cURL库发送POST请求到 xxx 的API,并处理 xxx的响应。

请注意,这只是一个基本示例,实际情况可能需要根据xxx的API文档和要求进行适当的调整和验证。

PHP中,可以使用反射来修改类的私有静态变量。以下是一个示例代码,演示如何使用反射来修改私有静态变量:

class MyClass {
    private static $privateStaticVariable = "Original Value";
    
    public static function getPrivateStaticVariable() {
        return self::$privateStaticVariable;
    }
}

// 使用反射修改私有静态变量
$reflectionClass = new ReflectionClass('MyClass');
$reflectionProperty = $reflectionClass->getProperty('privateStaticVariable');
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue(null, "New Value");

// 测试修改是否成功
echo MyClass::getPrivateStaticVariable(); // 输出:New Value

在上面的示例代码中,我们定义了一个名为MyClass的类,其中包含一个私有静态变量$privateStaticVariable和一个公共静态方法getPrivateStaticVariable(),用于获取私有静态变量的值。

然后,我们使用反射来获取MyClass类,并使用ReflectionClassReflectionProperty类来获取和修改私有静态变量。首先,我们创建了一个ReflectionClass对象,传入类名MyClass作为参数。然后,我们使用getProperty()方法获取私有静态变量的ReflectionProperty对象。接下来,我们将setAccessible(true)调用设置为true,以便能够访问私有变量。最后,我们使用setValue()方法将私有静态变量的值修改为"New Value"。

最后,我们调用MyClass::getPrivateStaticVariable()方法来获取修改后的私有静态变量的值,并将其输出到屏幕上。输出应该是"New Value",表示私有静态变量已成功修改。

请注意,使用反射来修改私有静态变量可能会破坏封装性和导致不可预测的结果。建议谨慎使用,并确保了解代码的结构和设计。

请简述一下 PHP Trait 的概念和用法

作为一个老程序员,在面试的时候被面试官用这个问题嘲讽了好一阵... 由于一直使用老的框架,再加上懒惰,导致我根本没法完整的回答这个问题,今天就带领各位一起学习(复习)这个概念,希望各位能有所收获。

1. Trait 是什么

Trait [treɪt] 翻译过来是 "特性"、"特点" 、"特质",是一种在 PHP 中复用代码的形式。

我们看下官方的解释:

Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。Trait 为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用 methodTraitClass 组合的语义定义了一种减少复杂性的方式,避免传统多继承和 Mixin 类相关典型问题。

上述说明可以提取出几个关键词:代码复用单继承减少复杂性

说到单继承,不得不提到另外一个特性:多态。多态和继承是软件开发中常用的代码复用方式,但是继承的方式虽然也能解决问题,但其思路违背了面向对象的原则,显得很粗暴;多态方式也可行,但不符合软件开发中的 DRYDon't repeat yourself ) 原则,增加了维护成本。

此时此刻,Trait 以一种全新的继承方式出现了,它既解决了前文叙述的两种继承方式的弊端,也相对优雅的实现了代码的复用。

简单说一下 Trait 在底层的运行原理:PHP 解释器在编译代码时会把 Trait 部分代码复制粘贴到类的定义体中,但是不会处理这个操作引入的不兼容问题。(是不是很厉害)

2. 定义和使用 Trait

接下来我还会沿用第二节课中的例子,但这次不是买手机,而是自己做手机。假设我们是一家比较特殊的手机厂商,为什么特殊呢,因为我们什么品牌的手机都做(就当是山寨工厂吧),废话不多说,我来说一下制作的规则:

假设我们掌握了三种手机的制作工艺,他们分别是:小米 Note3、三星 Galaxy S8 和 iPhone X,他们各有各的特点(相对于其他两种品牌独一无二)还有相同的特点(面部识别),为方便大家理解,我画了一张图(看不清图片的同学请点击图片查看大图):

Xnip2024-02-21_18-42-25.png

简单解释一下:众所周知,这三部手机都有面部识别的功能(上图左侧部分),这属于相同点,其实他们的相同点不止这些(比如都可以打电话、发短信等),而了解他们的同学也都知道,其中任何一部手机都有相对于其他手机没有的功能(上图右侧部分)。

下面我将用代码的形式讲解,当把这些手机抽象为 PHP 类的概念时,如何利用 PHP Trait 更好更优雅的实现这个图中的功能。

首先,我需要把『面部识别』这三个手机都有的功能抽象为一个 Trait,请看代码示例:

// 小米 Note3 三星 S8 iPhone X
// 共同拥有的面部识别功能
trait Faceable {
    protected $face_id = 0;
    // 就当我是获取面部信息的功能
    public function getFace()
    {
        //...
        return $this->face_id;
    }
    // 就当我是设置面部信息的功能
    public function setFace(string $face_id)
    {
        //...
        $this->face_id = $face_id;
    }
}

定义一个 Trait 是不是很简单,除特殊关键字以外,内部构造其实和 PHP 普通的类没啥区别。这里需要注意的是,Trait 的命名规范最好是以able 结尾,这样方便我们自己识别和理解。其次,建议每个文件只定义一种性状,这是良好的实践。

接下来就是定义这三部手机的类了,需要注意的是,我在实现这三部手机中特有的功能外,同时引用了我刚才定义的面部识别 Trait

// 小米 Note3
class MiNote3 {
    // 引入面部识别 Trait
    use Faceable;
    // 独有的 MIUI
    protected $miui;
    // 初始化MIUI
    public function __construct($miui)
    {
        $this->miui = $miui;
        $this->bootUI();
    }

    private function bootUI()
    {
        return $this->miui;
    }

    //...
}

注:小米的 MIUI 可以说是安卓阵营的佼佼者,用来当做其独特的特性不为过。

// 三星 GalaxyS8
class SamsangS8 {
    // 引入面部识别 Trait
    use Faceable;
    // 独有的 Bixby
    protected $bixby;
    
    public function __construct()
    {
        $this->sayHello();
    }

    private function sayHello()
    {
        echo "Hi I am Bixby!";
    }

    //...
}

注:Bixby 是三星近期发布的语音助手,虽然还在内测中,我有幸提前体验了一把,感觉各个方面都碾压苹果的 Siri 和其他语音助手。所以把这个 Bixby 的功能作为一个三星S8独有的特性,抽象出来一个类。

// iPhoneX
class iPhoneX {
    // 引入面部识别 Trait
    use Faceable;
    // 独有的 TrueDepth
    protected $true_depth;

    public function __construct()
    {
        $this->openCamera();
    }

    private function openCamera()
    {
        return $this->true_depth;
    }
    //...
}

注:iPhoneX 最好玩的特点莫过于前置的深感摄像头了,可以把表情动作赋给 emoji,这个功能就可以作为这个手机独有的特色抽象出来一个类。

通过以上示例,我们就可以把『面部识别』这三部手机都拥有的特性很轻松的组装到这三部手机中,使他们都具有完整性。用代码来说呢,就是每个类都使用了一个公共的 PHP Trait,在不改变自身的前提下,拥有了额外的属性。

3. Trait 的好处

有的人看完上述示例可能会有这样的疑问:与其像代码里这么写,我不如新建一个名为 Mobile 的类,在这个类里完成面部识别的功能,然后让三个手机的类直接继承 Mobile 类不就行了吗?比如:

// 手机公共类
class Mobile {
    protected $message;
    //...
    public function __construct($message)
    {
        $this->message = $message;
    }

    public function getMessage()
    {
        return $this->message;
    }

    // 实现了开关机 闹钟 音乐播放等功能...
    # code...
}

然后这样引用

// 小米Note3
class MiNote3 extends Mobile {
     // ...
}

// GalaxyS8
class SamsangS8 extends Mobile {
    // ...
}

答案是可以的,但是你有没有想过,除了『面部识别』,是不是还有其他的特性我没有列出来?比如三星和苹果都有的超大分辨率,小米没有;小米和三星都是安卓系统,而苹果不是。这样的关系,你如果都写在一个类里,由于 PHP 只有单继承的原因,会使你的 Mobile 类显得异常臃肿,难以解读。

但是你使用了 Trait 之后,我们只需要再提取出『安卓系统』和『高分辨率』这两个特性,就可以很方便的在这三个类里随意组合,而且还能保证你的代码非常清晰。

// 小米Note3
class MiNote3 {
    use Faceable,Androidable;
    // ...
}

// GalaxyS8
class SamsangS8 {
    use Faceable,Androidable,HDisplayable;
    // ...
}

// iPhoneX
class iPhoneX {
    use Faceable,HDisplayable;
    // ...
}

这样看起来是不是清晰很多呢?他不仅降低了代码的耦合性,还提升了代码的可读性。依我看来,他不光是某种特性的集合,更像是将某个功能细化了的代码块。

但还请大家记住,所有思路的设计没有对错之分,只有好坏之分。不要为了两段相同的能够写在一起而将完整的属性无脑拆拆拆,优雅设计的背后都有深思熟虑的设计过程。

原文地址 : https://zhuanlan.zhihu.com/p/31362082

karp

创建我自己的巨人