tuupola / branca-middleware
PSR-7和PSR-15 Branca身份验证中间件
Requires
- php: ^7.2|^8.0
- psr/http-message: ^1.0
- psr/http-server-middleware: ^1.0
- psr/log: ^1.0
- tuupola/branca: ^2.2.1
- tuupola/callable-handler: ^0.3.0|^0.4.0|^1.0
- tuupola/http-factory: ^1.1.0
Requires (Dev)
- equip/dispatch: ^2.0
- nyholm/psr7: ^1.3
- overtrue/phplint: ^1.0
- phpstan/phpstan: ^0.12.44
- phpunit/phpunit: ^7.0|^8.0|^9.0
- squizlabs/php_codesniffer: ^3.3.1
README
本中间件实现了Branca令牌身份验证。Branca类似于JWT,但更安全,令牌大小更小。该中间件可以与任何使用PSR-7或PSR-15风格中间件的框架一起使用。它已在Slim框架和Zend Expressive上进行了测试。
您可能还感兴趣阅读Branca作为JWT的替代方案?
本中间件不实现OAuth授权服务器,也不提供生成、颁发或存储身份验证令牌的方式。它仅当令牌通过header或cookie传递时解析和验证令牌。
安装
使用composer安装最新版本。
$ composer require tuupola/branca-middleware
如果使用Apache,请将以下内容添加到.htaccess
文件中。否则,PHP无法访问Authorization: Bearer
header。
RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
用法
配置选项以数组形式传递。唯一必需的参数是32字节的secret
,用于验证和加密令牌。
为了简单起见,示例显示了硬编码在代码中的secret
。在实际生活中,你应该将其存储在其他地方。一个好的选择是环境变量。你可以在开发中使用dotenv或类似工具。示例假设您正在使用Slim框架。
$app->add(new Tuupola\Middleware\BrancaAuthentication([ "secret" => "supersecretkeyyoushouldnotcommit" ]));
一个将您的密钥存储为环境变量的示例
$app->add(new Tuupola\Middleware\BrancaAuthentication([ "secret" => getenv("BRANCA_SECRET") ]));
当发起请求时,中间件尝试验证和解析令牌。如果找不到令牌或在验证和解析过程中出现错误,服务器将以401 Unauthorized
响应。
验证错误会在令牌被篡改或可选地令牌过期时触发。
可选参数
路径
可选的path
参数允许您指定网站的受保护部分。它可以是字符串或数组。您不需要指定每个URL。相反,将path
设置视为文件夹。在下面的示例中,所有以/api
开头的都将被验证。如果您不定义path
,则所有路由都将受保护。
$app->add(new Tuupola\Middleware\BrancaAuthentication([ "path" => "/api", /* or ["/api", "/admin"] */ "secret" => "supersecretkeyyoushouldnotcommit" ]));
忽略
使用可选的ignore
参数,您可以针对path
参数进行例外处理。在下面的示例中,所有以/api
和/admin
开头的都将进行验证,但/api/token
和/admin/ping
将不会被验证。
$app->add(new Tuupola\Middleware\BrancaAuthentication([ "path" => ["/api", "/admin"], "ignore" => ["/api/token", "/admin/ping"], "secret" => "supersecretkeyyoushouldnotcommit" ]));
TTL
Branca令牌在header中嵌入创建时间戳。您可以使用ttl
参数来控制应用程序接受的令牌的年龄。
$app->add(new Tuupola\Middleware\BrancaAuthentication([ "ttl" => 3600, /* 60 minutes */ "secret" => "supersecretkeyyoushouldnotcommit" ]));
Header
默认情况下,中间件尝试从Authorization
header中查找令牌。您可以使用header
参数更改header名称。
$app->add(new Tuupola\Middleware\BrancaAuthentication([ "header" => "X-Token", "secret" => "supersecretkeyyoushouldnotcommit" ]));
Regexp
默认情况下,中间件假设header的值在Bearer <token>
格式中。您可以使用regexp
参数更改此行为。例如,如果您有自定义header,例如X-Token: <token>
,则应传递header和regexp参数。
$app->add(new Tuupola\Middleware\BrancaAuthentication([ "header" => "X-Token", "regexp" => "/(.*)/", "secret" => "supersecretkeyyoushouldnotcommit" ]));
Cookie
如果既没有从环境变量也没有从头部找到令牌,中间件会尝试从名为 token
的cookie中查找。您可以使用 cookie
参数更改cookie名称。
$app->add(new Tuupola\Middleware\BrancaAuthentication([ "cookie" => "nekot", "secret" => "supersecretkeyyoushouldnotcommit" ]));
日志记录器
可选的 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\BrancaAuthentication([ "path" => "/api", "logger" => $logger, "secret" => "supersecretkeyyoushouldnotcommit" ]));
之前
只有当身份验证成功但在调用下一个中间件之前,才会调用 before
函数。您可以使用此功能在传递给下一个中间件之前更改请求。如果返回值不是 Psr\Http\Message\RequestInterface
,则返回值将被忽略。
$app->add(new Tuupola\Middleware\BrancaAuthentication([ "secret" => "supersecretkeyyoushouldnotcommit", "before" => function ($request, $arguments) { return $request->withAttribute("test", "test"); } ]));
之后
只有当身份验证成功并且已调用传入中间件堆栈之后,才会调用 after
函数。您可以使用此功能在传递给堆栈中的下一个传出中间件之前更改响应。如果返回值不是 Psr\Http\Message\ResponseInterface
,则返回值将被忽略。
$app->add(new Tuupola\Middleware\BrancaAuthentication([ "secret" => "supersecretkeyyoushouldnotcommit", "after" => function ($response, $arguments) { return $response->withHeader("X-Brawndo", "plants crave"); } ]));
错误
当身份验证失败时,会调用 error
。它接收最后一个错误消息作为参数。您可以使用此功能,例如,返回JSON格式的错误响应。
$app->add(new Tuupola\Middleware\BrancaAuthentication([ "secret" => "supersecretkeyyoushouldnotcommit", "error" => function ($request, $response, $arguments) { $data["status"] = "error"; $data["message"] = $arguments["message"]; return $response ->withHeader("Content-Type", "application/json") ->write(json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); } ]));
规则
可选的 rules
参数允许您传递规则,这些规则定义了请求是否应该进行身份验证。规则是一个可调用的,它接受请求作为参数。如果任何规则返回布尔值 false
,则请求将不会进行身份验证。
默认情况下,中间件配置看起来像这样。所有路径都使用除 OPTIONS
之外的所有请求方法进行身份验证。
$app->add(new Tuupola\Middleware\BrancaAuthentication([ "rules" => [ new Tuupola\Middleware\BrancaAuthentication\RequestPathRule([ "path" => "/", "ignore" => [] ]), new Tuupola\Middleware\BrancaAuthentication\RequestMethodRule([ "ignore" => ["OPTIONS"] ]) ] ]));
RequestPathRule
包含 path
参数和 ignore
参数。后者包含不应进行身份验证的路径。 RequestMethodRule
包含不应进行身份验证的请求方法 ignore
参数。将 ignore
视为白名单。
在99%的情况下,您不需要使用 rules
参数。它仅用于默认值不足的特殊情况。
安全性
Branga令牌本质上就是密码。您应该将其视为密码,并且始终使用HTTPS。如果中间件检测到通过HTTP的不安全使用,它将抛出 RuntimeException
。对于本地主机的请求,此规则会被放宽。要允许不安全的使用,您必须手动将其设置为 false
。
$app->add(new Tuupola\Middleware\BrancaAuthentication([ "secure" => false, "secret" => "supersecretkeyyoushouldnotcommit" ]));
或者,您可以列出您的开发主机以具有放宽的安全性。
$app->add(new Tuupola\Middleware\BrancaAuthentication([ "secure" => true, "relaxed" => ["localhost", "dev.example.com"], "secret" => "supersecretkeyyoushouldnotcommit" ]));
授权
默认情况下,中间件仅进行身份验证。这本身并不很有趣。Branga的优点在于您可以在令牌中传递额外的数据。这些数据可以包括例如范围,这可以用作授权。
如何实现令牌数据的存储或可能的授权实现取决于您。
假设您有一个包含请求范围和uid的JSON编码的有效负载。使用 before
回调,您可以向请求对象注入未编码的有效负载。
[ "uid" => 123, "scope" => ["read", "write", "delete"] ]
$app->add(new Tuupola\Middleware\BrancaAuthentication([ "secret" => "supersecretkeyyoushouldnotcommit", "before" => function ($request, $arguments) { $payload = json_decode($arguments["payload"], true); return $request->withAttribute("token", $payload); } ])); $app->delete("/item/{id}", function ($request, $response, $arguments) { if (in_array("delete", $request->token->scope)) { /* Code for deleting item */ } else { /* No scope so respond with 401 Unauthorized */ return $response->withStatus(401); } });
测试
您可以通过手动或自动在每次代码更改时运行测试来运行测试。自动测试需要entr 。
$ make test
$ brew install entr $ make watch
贡献
有关详细信息,请参阅CONTRIBUTING。
安全性
如果您发现任何与安全相关的错误,请通过电子邮件tuupola@appelsiini.net 而不是使用问题跟踪器。
许可
MIT许可(MIT)。有关更多信息,请参阅许可文件。