vymak/oauth2

Nette OAuth2 Provider bundle

dev-master 2019-04-08 11:35 UTC

This package is not auto-updated.

Last update: 2024-09-17 13:57:42 UTC


README

这个仓库正在开发中,非常不稳定。

需求

Drahak/OAuth2 需要 PHP 版本 5.3.0 或更高。唯一的依赖是 Nette 框架 2.0.x

安装与设置

最简单的方法是使用 Composer

$ composer require drahak/oauth2:@dev

然后在创建容器之前将以下代码添加到您的应用引导文件中

Drahak\OAuth2\DI\Extension::install($configurator);

或者在 config.neon 中注册它

extensions:
  restful: Drahak\Restful\DI\RestfulExtension

Neon 配置

oauth2:
	accessTokenLifetime: 3600 # 1 hour
	refreshTokenLifetime: 36000 # 10 hours
	authorizationCodeLifetime: 360 # 6 minutes
	storage: 'ndb' # allowed values: 'ndb', 'dibi'
	accessTokenStorage: 'Drahak\OAuth2\Storage\NDB\AccessTokenStorage'
	authorizationCodeStorage: 'Drahak\OAuth2\Storage\NDB\AuthorizationCodeStorage'
	clientStorage: 'Drahak\OAuth2\Storage\NDB\ClientStorage'
	refreshTokenStorage: 'Drahak\OAuth2\Storage\NDB\RefreshTokenStorage'
  • accessTokenLifetime - 访问令牌有效期(秒)
  • refreshTokenLifetime - 刷新令牌有效期(秒)
  • authorizationCodeLifetime - 授权代码有效期(秒)
  • storage - 存储将在默认 NDB 和 dibi 存储之间切换。您可以为每个存储部分使用自己的存储。

OAuth2

抽象协议流程

     +--------+                               +---------------+
     |        |------ Authorization Request ->|   Resource    |
     |        |                               |     Owner     |
     |        |<------ Authorization Grant ---|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |------- Authorization Grant -->| Authorization |
     | Client |                               |     Server    |
     |        |<--------- Access Token -------|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |---------- Access Token ------>|    Resource   |
     |        |                               |     Server    |
     |        |<------- Protected Resource ---|               |
     +--------+                               +---------------+

OAuth 角色

客户端 - 第三方应用程序

此应用程序想要从资源服务器获取用户数据,因此它需要获取访问令牌。

资源服务器 - API

客户端想要的数据。API 服务器使用访问令牌来访问用户信息。

资源所有者

允许访问其账户的一部分。

参见 OAuth 2 简化原始规范

OAuth 演示者

提供访问权限的演示者(IOAuthPresenter)。在基础中,它有 2 个主要方法,issueAccessTokenissueAuthorizationCode。简单的 OAuth(资源所有者)演示者可能看起来像这样

namespace MyApp\OAuth;

use Drahak\OAuth2\Grant\IGrant;
use Drahak\OAuth2\Application;
use Drahak\OAuth2\OAuthException;

class AuthorizationPresenter extends Application\OAuthPresenter
{

	/**
	 * Authorization
	 * @param string $response_type
	 * @param string $redirect_uri
	 * @param string|null $scope
	 */
	public function actionAuthorize($response_type, $redirect_uri, $scope = NULL)
	{
		if (!$this->user->isLoggedIn()) {
			$this->redirect('AnyUser:login', array('backlink' => $this->storeRequest()));
		}

		if ($response_type == 'code') {
			$this->issueAuthorizationCode($response_type, $redirect_uri, $scope);
		} else if ($response_type == 'token') {
			$this->issueAccessToken(IGrant::IMPLICIT, $redirect_uri);
		}
	}

	/**
	 * Access token provider
	 */
	public function actionToken()
	{
		try {
			$this->issueAccessToken();
		} catch (OAuthException $e) {
			$this->oauthError($e);
		}
	}

}

issueAccessToken 方法从 grant_type 参数中确定正确的授权类型。在出现错误时,抛出一个 OAuthException,该异常可以在默认实现中的 oauthError 方法中处理。

操作 authorize 更复杂。这用于生成授权代码(见下面 - 授权代码),但对于隐式授权类型,在这里生成访问令牌是必要的。如果用户未登录,则将用户重定向到某个登录页面,然后使用回链恢复授权请求。

授权类型

grant_type 参数确定。支持 OAuth2 规范中定义的基本授权类型:授权代码、隐式、密码、客户端凭据和刷新令牌。

  1. 授权代码

这种授权类型非常适合可以安全存储客户端密钥代码的第三方应用程序。

要生成访问令牌,您首先需要获取授权代码。您可以通过调用 issueAuthorizationCodeIOAuthPresenter 获取它。

授权代码请求
GET //oauth.presenter.url/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=email
  • [必需] response_type - 您想要生成授权 code
  • [必需] client_id - 请求访问令牌的客户端 ID(例如应用程序)
  • [必需] redirect_uri - 成功或出错时重定向的 URL 地址
  • [可选] scope - 指定访问请求的作用域
授权代码响应

在任何情况下(错误或成功),资源所有者都会使用 redirect_uri 将客户端重定向回,其中包含作为查询参数的授权代码

//redirect_uri/?code=AnlSCIWYbchsCc5sdc5ac4caca8a2

//redirect_uri/?error=unauthorized_client&error_description=Client+is+not+found

由于您有了授权代码,因此可以发出访问令牌请求(数据以 application/x-www-form-urlencoded 格式提供)

访问令牌请求
POST //oauth.presenter.url/token
	grant_type=authorization_code
	&code=AUTHORIZATION_CODE
	&client_id=CLIENT_ID
	&client_secret=CLIENT_SECRET
  • 【必填】grant_type - 此参数表示OAuth使用授权码
  • 【必填】code - 从资源所有者处获得的授权码
  • [必需] client_id - 请求访问令牌的客户端 ID(例如应用程序)
  • 【必填】client_secret - 客户端(例如应用程序)的密钥,用于请求访问令牌
访问令牌响应
{
	"access_token": "AnlSCIWYbchsCc5sdc5ac4caca8a2",
	"token_type": "bearer",
	"expires_in": 3600,
	"refresh_token": "DS6SA512ADCVa51adc54VDS51VD5"
}

发生错误时,提供JSON响应

{
	"error": "invalid_request",
	"error_description": "Invalid authorization code"
}
  1. 隐式授权

用于基于浏览器(Web)或移动应用程序,在这些应用程序中,您无法安全地存储客户端密钥,因此您不能使用它来获取访问令牌。

访问令牌请求
GET //oauth.presenter.url/authorization?response_type=token&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=email
  • 【必填】response_type - 由于您从资源所有者请求访问令牌,您必须说明您想要一个访问令牌(而不是授权码)
  • [必需] client_id - 请求访问令牌的客户端 ID(例如应用程序)
  • 【必填】redirect_uri - 成功或错误时重定向到的URL
  • [可选] scope - 指定访问请求的作用域
访问令牌响应

重定向到 redirect_uri

//redirect_uri/#access_token=AnlSCIWYbchsCc5sdc5ac4caca8a2&expires_in=3600&token_type=bearer

发生错误时,重定向到

//redirect_uri/#error=unauthorized_client&error_description=Client+is+not+found
  1. 密码

用于受信任(通常是第一方)应用程序,在这种情况下,您完全信任客户端,因为您是从真实用户的凭据(用户名、密码)生成访问令牌。

访问令牌请求
POST //oauth.presenter.url/token
	grant_type=password
	&username=USERNAME
	&password=PASSWORD
	&client_id=CLIENT_ID
  • 【必填】grant_type - 密码授权类型意外地使用标识符 password
  • [必需] client_id - 请求访问令牌的客户端 ID(例如应用程序)
  • 【必填】username - 真实用户的用户名
  • 【可选】password - 真实用户的密码
访问令牌响应
{
	"access_token": "AnlSCIWYbchsCc5sdc5ac4caca8a2",
	"token_type": "bearer",
	"expires_in": 3600,
	"refresh_token": "DS6SA512ADCVa51adc54VDS51VD5"
}

发生错误时

{
	"error": "invalid_request",
	"error_description": "Invalid authorization code"
}
  1. 客户端凭据

如果应用程序需要在任何特定用户之外获取其自己的访问令牌,这可能是一个最佳方式。

访问令牌请求
POST //oauth.presenter.url/token
	grant_type=client_credentials
	&client_id=CLIENT_ID
	&client_SECRET=CLIENT_SECRET
  • 【必填】grant_type - 密码授权类型意外地使用标识符 password
  • [必需] client_id - 请求访问令牌的客户端 ID(例如应用程序)
  • 【必填】client_secret - 客户端(例如应用程序)的密钥,用于请求访问令牌
访问令牌响应
{
	"access_token": "AnlSCIWYbchsCc5sdc5ac4caca8a2",
	"token_type": "bearer",
	"expires_in": 3600,
	"refresh_token": "DS6SA512ADCVa51adc54VDS51VD5"
}

发生错误时

{
	"error": "invalid_request",
	"error_description": "Invalid authorization code"
}
  1. 刷新令牌

用于在不进行身份验证过程的情况下恢复(实际上是重新生成)访问令牌。刷新令牌几乎与每种授权类型(除隐式授权外)一起提供。

请求刷新令牌
POST //oauth.presenter.url/token
	grant_type=refresh_token
	&refresh_token=DS6SA512ADCVa51adc54VDS51VD5
	&client_id=CLIENT_ID
  • 【必填】grant_type - 刷新令牌标识符
  • 【必填】refresh_token - 刷新令牌本身,您几乎可以从任何访问令牌中获得它
  • [必需] client_id - 请求访问令牌的客户端 ID(例如应用程序)
访问令牌响应
{
	"access_token": "AnlSCIWYbchsCc5sdc5ac4caca8a2",
	"token_type": "bearer",
	"expires_in": 3600,
	"refresh_token": "DS6SA512ADCVa51adc54VDS51VD5"
}

发生错误时

{
	"error": "invalid_request",
	"error_description": "Invalid refresh token"
}