rnd-cosoft / api-tools-oauth2
Laminas 模块,用于实现 OAuth2 服务器
Requires
- php: ~8.1.0 || ~8.2.0 || ~8.3.0
- bshaffer/oauth2-server-php: ^1.14.1
- laminas/laminas-crypt: ^3.5
- laminas/laminas-http: ^2.15.1
- laminas/laminas-mvc: ^2.7.15 || ^3.3.0
- laminas/laminas-mvc-i18n: ^1.3
- laminas/laminas-servicemanager: ^3.11.1
- rnd-cosoft/api-tools-api-problem: ^1.5
- rnd-cosoft/api-tools-content-negotiation: ^1.8.0
- webmozart/assert: ^1.10
Requires (Dev)
- laminas/laminas-authentication: ^2.9
- laminas/laminas-coding-standard: ~2.3.0
- laminas/laminas-db: ^2.13
- laminas/laminas-i18n: ^2.12.0
- laminas/laminas-log: ^2.15
- laminas/laminas-modulemanager: ^2.10
- laminas/laminas-serializer: ^2.11
- laminas/laminas-test: ^4.0.0
- mockery/mockery: ^1.3.2
- phpspec/prophecy-phpunit: ^2.0.1
- phpunit/phpunit: ^9.5.10
- psalm/plugin-phpunit: ^0.16
- vimeo/psalm: ^4.23
Suggests
- alcaeus/mongo-php-adapter: ^1.0.5, if you are using ext/mongodb and wish to use the MongoAdapter for OAuth2 credential storage.
Replaces
- 1.10.x-dev
- 1.10.2
- 1.10.0
- 1.9.x-dev
- 1.9.0
- 1.8.x-dev
- 1.8.0
- 1.7.x-dev
- 1.7.2
- 1.7.1
- 1.7.0
- 1.6.x-dev
- 1.6.0
- 1.5.2
- 1.5.1
- 1.5.0p2
- 1.5.0p1
- 1.5.0
- 1.4.0p2
- 1.4.0p1
- 1.4.0
- 1.3.3p2
- 1.3.3p1
- 1.3.3
- 1.3.2p2
- 1.3.2p1
- 1.3.2
- 1.3.1p2
- 1.3.1p1
- 1.3.1
- 1.3.0p2
- 1.3.0p1
- 1.3.0
- 1.2.1p2
- 1.2.1p1
- 1.2.1
- 1.2.0p2
- 1.2.0p1
- 1.2.0
- 1.1.3p2
- 1.1.3p1
- 1.1.3
- 1.1.2p2
- 1.1.2p1
- 1.1.2
- 1.1.1p2
- 1.1.1p1
- 1.1.1
- 1.1.0p2
- 1.1.0p1
- 1.1.0
- 1.0.3p2
- 1.0.3p1
- 1.0.3
- 1.0.2p2
- 1.0.2p1
- 1.0.2
- 1.0.1p2
- 1.0.1p1
- 1.0.1
- 1.0.0p2
- 1.0.0p1
- 1.0.0
- 1.0.0beta3
- 1.0.0beta2
- 1.0.0beta1
- 0.9.1p2
- 0.9.1p1
- 0.9.1
- 0.9.0p2
- 0.9.0p1
- 0.9.0
- 0.8.0p2
- 0.8.0p1
- 0.8.0
- 0.7.0p2
- 0.7.0p1
- 0.7.0
This package is not auto-updated.
Last update: 2024-09-13 12:33:05 UTC
README
🇷🇺 俄罗斯公民
我们是 Laminas 的成员,来自不同的国家。我们中许多人都有俄罗斯和乌克兰的朋友、亲戚和同事。我们中的一些人出生在俄罗斯。我们中的一些人现在住在俄罗斯。我们中的一些人的祖父母在第二次世界大战中与法西斯主义者作战。这里没有人支持法西斯主义。
我们中有一个成员有一个乌克兰亲戚,她和儿子一起逃离了家园。火车因前方道路上的轰炸而延误。我们有一些朋友在防空洞里躲避。我们在空袭后焦急地追踪他们的消息,空袭无差别地攻击医院、学校、幼儿园和房屋。我们不是从任何媒体上得知此事的。这是我们的亲身经历。
您信任我们足够,以至于使用我们的程序,我们请求您再次信任我们。我们需要您的帮助。走出家门,抗议这场无意义的战争。停止血腥。说“停止战争!”
🇺🇸 致俄罗斯公民
我们在 Laminas 来自世界各地。我们中许多人都有俄罗斯和乌克兰的朋友、家人和同事。我们中的一些人出生在俄罗斯。我们中的一些人现在住在俄罗斯。我们中的一些人的祖父母在第二次世界大战中与纳粹作战。这里没有人支持法西斯主义。
我们团队中有一个成员有一个乌克兰亲戚,她和儿子一起逃离了家园。火车因前方道路上的轰炸而延误。我们有一些朋友在防空洞里躲避。我们在空袭后焦急地追踪他们的消息,空袭无差别地攻击医院、学校、幼儿园和房屋。我们不是从任何媒体上得知此事的。这是我们的亲身经历。
您信任我们足够,以至于使用我们的软件。我们要求您信任我们说出真相。我们需要您的帮助。走出家门,抗议这场无意义的战争。停止血腥。说“停止战争!”
Laminas 模块,用于 OAuth2 认证。
此模块使用 Brent Shaffer 的 oauth2-server-php 库提供 OAuth2 支持。
要求
请参阅 composer.json 文件。
安装
您可以使用以下方式安装
$ composer require laminas-api-tools/api-tools-oauth2
如果您使用 ext/mongodb,您还需要安装一个兼容性包
$ composer require alcaeus/mongo-php-adapter
最后,您需要将以下模块添加到应用程序的配置中
'modules' => [ /* ... */ 'Laminas\ApiTools\ApiProblem', 'Laminas\ApiTools\ContentNegotiation', 'Laminas\ApiTools\OAuth2', ],
laminas-component-installer
如果您使用 laminas-component-installer,该插件将为您安装 api-tools-oauth2 及其其他 Laminas API Tools 依赖项作为模块。
配置
此模块使用任何 PDO 支持的数据库来管理 OAuth2 信息(用户、客户端、令牌等)。数据库结构存储在 data/db_oauth2.sql
中。
CREATE TABLE oauth_clients ( client_id VARCHAR(80) NOT NULL, client_secret VARCHAR(80) NOT NULL, redirect_uri VARCHAR(2000) NOT NULL, grant_types VARCHAR(80), scope VARCHAR(2000), user_id VARCHAR(255), CONSTRAINT clients_client_id_pk PRIMARY KEY (client_id) ); CREATE TABLE oauth_access_tokens ( access_token VARCHAR(40) NOT NULL, client_id VARCHAR(80) NOT NULL, user_id VARCHAR(255), expires TIMESTAMP NOT NULL, scope VARCHAR(2000), CONSTRAINT access_token_pk PRIMARY KEY (access_token) ); CREATE TABLE oauth_authorization_codes ( authorization_code VARCHAR(40) NOT NULL, client_id VARCHAR(80) NOT NULL, user_id VARCHAR(255), redirect_uri VARCHAR(2000), expires TIMESTAMP NOT NULL, scope VARCHAR(2000), id_token VARCHAR(2000), CONSTRAINT auth_code_pk PRIMARY KEY (authorization_code) ); CREATE TABLE oauth_refresh_tokens ( refresh_token VARCHAR(40) NOT NULL, client_id VARCHAR(80) NOT NULL, user_id VARCHAR(255), expires TIMESTAMP NOT NULL, scope VARCHAR(2000), CONSTRAINT refresh_token_pk PRIMARY KEY (refresh_token) ); CREATE TABLE oauth_users ( username VARCHAR(255) NOT NULL, password VARCHAR(2000), first_name VARCHAR(255), last_name VARCHAR(255), CONSTRAINT username_pk PRIMARY KEY (username) ); CREATE TABLE oauth_scopes ( type VARCHAR(255) NOT NULL DEFAULT "supported", scope VARCHAR(2000), client_id VARCHAR (80), is_default SMALLINT DEFAULT NULL ); CREATE TABLE oauth_jwt ( client_id VARCHAR(80) NOT NULL, subject VARCHAR(80), public_key VARCHAR(2000), CONSTRAINT jwt_client_id_pk PRIMARY KEY (client_id) );
PostgreSQL
我们还在
data/db_oauth2_postgresql.sql
中提供了 PostgreSQL 特定的 DDL。
出于安全原因,我们使用 bcrypt 算法(通过类 Laminas\Crypt\Password\Bcrypt)加密了字段 client_secret
(表 oauth_clients
)和 password
(表 oauth_users
)。
为了配置数据库访问的api-tools-oauth2模块,您需要将文件config/oauth2.local.php.dist
复制到您的Laminas应用程序中的config/autoload/oauth2.local.php
,并编辑它以提供您的数据库凭据(DNS、用户名、密码)。
我们还包含了一个SQLite数据库,在data/dbtest.sqlite
中,您可以在测试环境中使用。在这个数据库中,您将找到一个具有client_id
"testclient"和client_secret
"testpass"的测试客户端账户。如果您想使用这个数据库,您可以将您的config/autoload/oauth2.local.php
文件配置如下
return array( 'api-tools-oauth2' => array( 'db' => array( 'dsn' => 'sqlite:<path to api-tools-oauth2 module>/data/dbtest.sqlite', ), ), );
Mongo配置
Mongo OAuth2适配器通过添加与api-tools的其他部分相同的密码加密来包装bshaffer适配器。所需集合与上述PDO适配器中的相同。要创建OAuth2客户端,请在oauth_clients集合中插入以下文档
{ "client_id": "testclient", "client_secret": "$2y$14$f3qml4G2hG6sxM26VMq.geDYbsS089IBtVJ7DlD05BoViS9PFykE2", "redirect_uri": "/oauth/receivecode", "grant_types": null }
用户ID提供者
当用户请求授权码时,他们可能将他们的用户ID作为请求参数提供给/oauth/authorize
路由。这将随着用户通过oauth2过程,将user_id
存储在access_token
、refresh_token
和authorization_code
表中。
用户可能通过Laminas\Authentication\AuthenticationService
或其他认证方式认证。当用户必须在使用/oauth/authorize
路由之前提供认证时,应该使用已认证的用户ID。这可以通过服务管理器别名Laminas\ApiTools\OAuth2\Provider\UserId
来完成。
默认的用户ID提供者使用请求查询参数user_id
,并通过类Laminas\ApiTools\OAuth2\Provider\UserId\Request
处理。
本仓库提供了一个替代提供者,Laminas\ApiTools\OAuth2\Provider\UserId\AuthorizationService
,它使用Laminas\Authentication\AuthenticationService
来获取身份。要将用户ID提供者更改为使用此服务,更改Laminas\ApiTools\OAuth2\Provider\UserId
服务别名以指向它
return array( 'service_manager' => 'aliases' => array( 'Laminas\ApiTools\OAuth2\Provider\UserId' => 'Laminas\ApiTools\OAuth2\Provider\UserId\AuthenticationService', ), ), );
如何测试OAuth2
要测试OAuth2模块,您必须在oauth2数据库中添加一个client_id
和一个client_secret
。如果您正在使用SQLite测试数据库,则不需要添加client_id
;只需使用默认的"testclient"/"testpass"账户。
因为我们使用bcrypt
算法加密密码,所以您需要使用Laminas的Laminas\Crypt\Password\Bcrypt
类来加密密码。我们提供了一个简单的脚本在/bin/bcrypt.php
中,用于生成用户密码的哈希值。您可以从命令行使用此工具,语法如下
php bin/bcrypt.php testpass
其中"testpass"是要加密的用户密码。上述命令的输出将是用户密码的哈希值,一个60字节的字符串,如下所示
$2y$14$f3qml4G2hG6sxM26VMq.geDYbsS089IBtVJ7DlD05BoViS9PFykE2
在生成密码的哈希值(client_secret
)之后,您可以使用以下SQL语句在数据库中添加一个新的client_id
INSERT INTO oauth_clients ( client_id, client_secret, redirect_uri) VALUES ( "testclient", "$2y$14$f3qml4G2hG6sxM26VMq.geDYbsS089IBtVJ7DlD05BoViS9PFykE2", "/oauth/receivecode" );
要测试OAuth2模块,您可以使用HTTP客户端,如HTTPie或CURL。下面的例子使用HTTPie和测试账户"testclient"/"testpass"。
请求令牌(client_credentials)
您可以使用以下HTTPie命令请求OAuth2令牌
http --auth testclient:testpass -f POST http://<URL of your Laminas app>/oauth grant_type=client_credentials
此POST请求使用client_credentials模式向OAuth2服务器请求新令牌。这在应用程序访问的机器到机器交互中很典型。如果一切正常,您应该收到如下响应
{ "access_token":"03807cb390319329bdf6c777d4dfae9c0d3b3c35", "expires_in":3600, "token_type":"bearer", "scope":null }
安全提示:因为此POST使用基本HTTP认证,所以client_secret
在HTTP请求中以明文形式暴露。为了保护此调用,需要TLS/SSL连接。
授权(code)
如果您需要将OAuth2服务集成到Web应用程序中,您需要使用授权码授权类型。这种授权类型需要一个批准步骤来授权Web应用程序。这一步骤通过一个简单的表单来实现,该表单请求用户批准访问资源(账户)。本模块提供了一个简单的表单来授权特定客户端。此表单可以通过以下URL通过浏览器访问:
http://<URL of your Laminas app>/oauth/authorize?response_type=code&client_id=testclient&redirect_uri=/oauth/receivecode&state=xyz
此页面将渲染一个表单,要求用户授权或拒绝客户端的访问。如果他们授权访问,OAuth2模块将回复一个授权码。此代码必须用于请求OAuth2令牌;以下HTTPie命令提供了一个如何操作的示例:
http --auth testclient:testpass -f POST http://<URL of your Laminas app>/oauth grant_type=authorization_code&code=YOUR_CODE&redirect_uri=/oauth/receivecode
在客户端场景(例如移动端)中,您无法以安全的方式存储客户端凭据,您不能使用之前的流程。在这种情况下,我们可以使用隐式授权。这与授权码类似,但授权请求返回的不是授权码,而是一个令牌。
要使模块能够接受隐式授权类型,您需要将config/autoload/oauth2.local.php
文件中的allow_implicit
配置更改为true
。
return array( 'api-tools-oauth2' => array( // ... 'allow_implicit' => true, // ... ), );
要从客户端请求令牌,您需要通过OAuth2服务器请求授权。
http://<URL of your Laminas app>/oauth/authorize?response_type=token&client_id=testclient&redirect_uri=/oauth/receivecode&state=xyz
此请求将渲染与上一个示例相同的授权表单。如果您授权访问,请求将被重定向到/oauth/receivecode
(如上述示例中提供的redirect_uri
参数),并在URI片段中指定access_token
,如下所示:
/oauth/receivecode#access_token=559d8f9b6bedd8d94c8e8d708f87475f4838c514&expires_in=3600&token_type=Bearer&state=xyz
要获取access_token
,您可以通过解析URI来获取。我们使用URI片段传递access_token
,因为这样令牌不会被传输到服务器;它只会对客户端可用。
在JavaScript中,您可以使用以下代码片段轻松解析URI:
// function to parse fragment parameters var parseQueryString = function( queryString ) { var params = {}, queries, temp, i, l; // Split into key/value pairs queries = queryString.split("&"); // Convert the array of strings into an object for ( i = 0, l = queries.length; i < l; i++ ) { temp = queries[i].split('='); params[temp[0]] = temp[1]; } return params; }; // get token params from URL fragment var tokenParams = parseQueryString(window.location.hash.substr(1));
撤销(代码)
从版本1.4.0开始,您可以撤销访问令牌。默认情况下,撤销通过向路径/oauth/revoke
发送POST请求进行,该路径期望包含以下有效负载:
token
,要撤销的OAuth2访问令牌。token_type_hint => 'access_token'
,表示正在撤销访问令牌。
有效负载可以是application/x-www-form-urlencoded
或JSON格式。
访问测试资源
当您获得有效的令牌时,您可以访问受限的API资源。OAuth2模块附带了一个可使用URL/oauth/resource
访问的测试资源。这是一个简单的资源,返回JSON数据。
要访问测试资源,您可以使用以下HTTPie命令:
http -f POST http://<URL of your Laminas app>/oauth/resource access_token=000ab5afab4cbbbda803fb9e50e7943f5e766748 # or http http://<<URL of your Laminas app>/oauth/resource "Authorization:Bearer 000ab5afab4cbbbda803fb9e50e7943f5e766748"
如您所见,OAuth2模块支持通过POST使用access_token
值或使用Bearer授权头来访问数据。
如何使用OAuth2保护您的API
您可以使用以下代码(例如,在控制器顶部)来保护您的API:
if (!$this->server->verifyResourceRequest(OAuth2Request::createFromGlobals())) { // Not authorized return 401 error $this->getResponse()->setStatusCode(401); return; }
其中$this->server
是OAuth2\Server
的一个实例(请参阅AuthController.php)。