推荐使用:PSR-7与PSR-15兼容的JWT认证中间件
这个中间件实现了一种基于JSON Web Token(JWT)的认证方案,最初是为了Slim框架设计,但任何采用PSR-7和PSR-15风格中间件的框架都可以使用。它已在Slim Framework和Zend Expressive上测试通过。
请注意,您正在查看的是适用于PHP 7.1及更高版本的3.x分支文档。如果您使用的是旧版PHP,请查阅2.x分支。这两个分支不向下兼容,升级指南见UPGRADING。
该中间件不提供OAuth 2.0授权服务器功能,也不处理令牌的生成、发行或存储。它仅解析和验证通过头文件或Cookie传递的令牌,这对于将JSON Web Tokens作为API密钥非常有用,如这篇文章所述。
安装
通过Composer安装最新版本。
$ composer require tuupola/slim-jwt-auth
如果使用Apache,需要在.htaccess
文件中添加以下内容,以使PHP可以访问Authorization: Bearer
头部信息。
RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
使用方法
配置参数作为一个数组传递。唯一必需的参数是用于验证签名的secret
。再次强调,secret
不是令牌本身,而是用来签署令牌的密钥。为了简化示例,这里将secret
硬编码在代码中,但在实际应用中应将其存储在其他地方,例如使用dotenv库的环境变量。
$app = new Slim\App;
$app->add(new Tuupola\Middleware\JwtAuthentication([
"secret" => "supersecretkeyyoushouldnotcommittogithub"
]));
一个示例,其中你的秘密存储为环境变量:
$app = new Slim\App;
$app->add(new Tuupola\Middleware\JwtAuthentication([
"secret" => getenv("JWT_SECRET")
]));
当请求被发出时,中间件尝试验证并解码令牌。如果没有找到令牌或者在验证和解码过程中出现错误,服务器会响应401未经授权
。
验证错误通常发生在令牌已被篡改或过期的情况下。关于所有可能的验证错误,请参阅jwt库的源代码。
可选参数
路径
可选的path
参数允许您指定网站受保护的部分。它可以是一个字符串或一个数组。不必指定每个URL,而应该考虑path
设置为一个目录。在下面的例子中,所有以/api
开头的路由都会进行身份验证。如果不定义path
,所有路由都将受到保护。
$app = new Slim\App;
$app->add(new Tuupola\Middleware\JwtAuthentication([
"path" => "/api", /* 或者 ["/api", "/admin"] */
"secret" => "supersecretkeyyoushouldnotcommittogithub"
]));
忽略
可选的ignore
参数使您可以为path
参数指定例外情况。在下面的示例中,除/api/token
和/admin/ping
之外,以/api
或/admin
开头的所有路由都将进行身份验证。
$app = new Slim\App;
$app->add(new Tuupola\Middleware\JwtAuthentication([
"path" => ["/api", "/admin"],
"ignore" => ["/api/token", "/admin/ping"],
"secret" => "supersecretkeyyoushouldnotcommittogithub"
]));
头部
默认情况下,中间件会在Authorization
头部寻找令牌。您可以使用header
参数更改头部名称。
$app = new Slim\App;
$app->add(new Tuupola\Middleware\JwtAuthentication([
"header" => "X-Token",
"secret" => "supersecretkeyyoushouldnotcommittogithub"
]));
正则表达式
默认情况下,中间件假设头部值遵循Bearer <token>
的格式。您可以使用regexp
参数自定义这种行为。例如,如果你有一个自定义头部X-Token: <token>
,你应该同时传递header
和regexp
参数。
$app = new Slim\App;
$app->add(new Tuupola\Middleware\JwtAuthentication([
"header" => "X-Token",
"regexp" => "/(.*)/",
"secret" => "supersecretkeyyoushouldnotcommittogithub"
]));
Cookie
如果未从环境或头部找到令牌,中间件会尝试从名为token
的cookie中查找。您可以使用cookie
参数更改cookie名称。
$app = new Slim\App;
$app->add(new Tuupola\Middleware\JwtAuthentication([
"cookie" => "nekot",
"secret" => "supersecretkeyyoushouldnotcommittogithub"
]));
算法
您可以使用algorithm
参数设置支持的算法。这可以是字符串或字符串数组。默认值是["HS256", "HS512", "HS384"]
。支持的算法有HS256
,HS384
,HS512
和RS256
。注意启用HS256
和RS256
可能导致安全风险。
$app = new Slim\App;
$app->add(new Tuupola\Middleware\JwtAuthentication([
"secret" => "supersecretkeyyoushouldnotcommittogithub",
"algorithm" => ["HS256", "HS384"]
]));
属性
当令牌成功解码且认证成功后,解码的令牌内容将以token
属性形式保存到$request
对象中。您可以使用attribute
参数来改变这一行为。将其设为null
或false
以禁用这一功能。
$app = new Slim\App;
$app->add(new Tuupola\Middleware\JwtAuthentication([
"attribute" => "jwt",
"secret" => "supersecretkeyyoushouldnotcommittogithub"
]));
/* ... */
$decoded = $request->getAttribute("jwt");
日志器
可选的logger
参数允许您传递一个符合PSR-3的日志记录器,帮助进行调试或其他应用程序日志记录需求。
use Monolog\Logger;
use Monolog\Handler\RotatingFileHandler;
$app = new Slim\App;
$logger = new Logger("slim");
$rotating = new RotatingFileHandler(__DIR__ . "/logs/slim.log", 0, Logger::DEBUG);
$logger->pushHandler($rotating);
$app->add(new Tuupola\Middleware\JwtAuthentication([
"path" => "/api",
"logger" => $logger,
"secret" => "supersecretkeyyoushouldnotcommittogithub"
]));
前置处理
前置处理函数只在认证成功但在调用下一个中间件之前执行。您可以利用此特性在将请求传递给中间件堆栈中的下一个中间件之前对其进行修改。如果返回非Psr\Http\Message\ServerRequestInterface
类型的值,其返回值会被忽略。
$app = new Slim\App;
$app->add(new Tuupola\Middleware\JwtAuthentication([
"secret" => "supersecretkeyyoushouldnotcommittogithub",
"before" => function ($request, $arguments) {
return $request->withAttribute("test", "test");
}
]));
后置处理
后置处理函数只在认证成功且中间件堆栈已调用完毕之后执行。您可以用它在将响应传递到下一个出站中间件之前对其进行修改。如果返回非Psr\Http\Message\ResponseInterface
类型的值,其返回值会被忽略。
$app = new Slim\App;
$app->add(new Tuupola\Middleware\JwtAuthentication([
"secret" => "supersecretkeyyoushouldnotcommittogithub",
"after" => function ($response, $arguments) {
return $response->withHeader("X-Brawndo", "plants crave");
}
]));
注:
after
和before
回调函数都接收原始令牌字符串以及解码后的声明,这些内容通过arguments
参数传入。
错误处理
当认证失败时,error
函数会被调用。它会接收到最后一个错误消息作为参数。您可以使用它返回JSON格式化的错误响应。
$app = new Slim\App;
$app->add(new Tuupola\Middleware\JwtAuthentication([
"secret" => "supersecretkeyyoushouldnotcommittogithub",
"error" => function ($response, $arguments) {
$data["status"] = "error";
$data["message"] = $arguments["message"];
$response->getBody()->write(
json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)
);
return $response->withHeader("Content-Type", "application/json")
}
]));
规则
可选的rules
参数允许您传入规则,定义哪些请求应进行认证,哪些不应。规则是一个接收请求作为参数的可调用对象。如果任何一个规则返回布尔false
,请求将不会被认证。
默认的中间件配置如下,所有路径对所有请求方法进行认证,除了OPTIONS
。
$app = new Slim\App;
$app->add(new Tuupola\Middleware\JwtAuthentication([
"secret" => "supersecretkeyyoushouldnotcommittogithub",
"rules" => function (Psr\Http\Message\RequestInterface $request) {
// 实现您的规则...
}
]));
这是一个强大的工具,可以帮助您轻松地实现基于JWT的安全认证。无论是在简单的RESTful API还是复杂的应用程序中,它都能提供强大的保护,并且易于集成到现有的PHP项目中。立即尝试并提升您的项目安全性吧!