isigar/oauth2

Nette OAuth2 Provider 套件

1.1 2018-05-18 08:24 UTC

This package is not auto-updated.

Last update: 2024-09-29 05:41:56 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);
		}
	}

}

方法 issueAccessTokengrant_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. 隐式

用于基于浏览器(网页)或移动应用程序,在这种情况下,您无法安全地保护客户端密钥,因此您不能使用它来获取访问令牌。

请求访问令牌
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"
}