agencegw / oauth2-azure
为 PHP League OAuth2-Client 提供的 Azure Active Directory OAuth 2.0 客户端提供程序
Requires
- php: ^7.1|^8.0
- ext-json: *
- ext-openssl: *
- firebase/php-jwt: ~3.0||~4.0||~5.0||~6.0
- league/oauth2-client: ~2.0
This package is not auto-updated.
Last update: 2024-09-26 18:53:00 UTC
README
本软件包提供了对 Microsoft Azure Active Directory 的支持,用于 PHP League 的 OAuth 2.0 客户端。
目录
- 安装
- 用法
- 制作 API 请求
- 资源所有者
- 更新 - Microsoft Graph
- 新增 - 保护您的 API - 实验性
- Azure Active Directory B2C - 实验性
- 多用途刷新令牌 - 实验性
- 已知用户
- 贡献
- 致谢
- 支持
- 许可协议
安装
要安装,请使用 composer
composer require thenetworg/oauth2-azure
用法
用法与 The League 的 OAuth 客户端相同,使用 \TheNetworg\OAuth2\Client\Provider\Azure
作为提供程序。
授权码流
$provider = new TheNetworg\OAuth2\Client\Provider\Azure([
'clientId' => '{azure-client-id}',
'clientSecret' => '{azure-client-secret}',
'redirectUri' => 'https://example.com/callback-url',
//Optional
'scopes' => ['openid'],
//Optional
'defaultEndPointVersion' => '2.0'
]);
// Set to use v2 API, skip the line or set the value to Azure::ENDPOINT_VERSION_1_0 if willing to use v1 API
$provider->defaultEndPointVersion = TheNetworg\OAuth2\Client\Provider\Azure::ENDPOINT_VERSION_2_0;
$baseGraphUri = $provider->getRootMicrosoftGraphUri(null);
$provider->scope = 'openid profile email offline_access ' . $baseGraphUri . '/User.Read';
if (isset($_GET['code']) && isset($_SESSION['OAuth2.state']) && isset($_GET['state'])) {
if ($_GET['state'] == $_SESSION['OAuth2.state']) {
unset($_SESSION['OAuth2.state']);
// Try to get an access token (using the authorization code grant)
/** @var AccessToken $token */
$token = $provider->getAccessToken('authorization_code', [
'scope' => $provider->scope,
'code' => $_GET['code'],
]);
// Verify token
// Save it to local server session data
return $token->getToken();
} else {
echo 'Invalid state';
return null;
}
} else {
// // Check local server's session data for a token
// // and verify if still valid
// /** @var ?AccessToken $token */
// $token = // token cached in session data, null if not found;
//
// if (isset($token)) {
// $me = $provider->get($provider->getRootMicrosoftGraphUri($token) . '/v1.0/me', $token);
// $userEmail = $me['mail'];
//
// if ($token->hasExpired()) {
// if (!is_null($token->getRefreshToken())) {
// $token = $provider->getAccessToken('refresh_token', [
// 'scope' => $provider->scope,
// 'refresh_token' => $token->getRefreshToken()
// ]);
// } else {
// $token = null;
// }
// }
//}
//
// If the token is not found in
// if (!isset($token)) {
$authorizationUrl = $provider->getAuthorizationUrl(['scope' => $provider->scope]);
$_SESSION['OAuth2.state'] = $provider->getState();
header('Location: ' . $authorizationUrl);
exit;
// }
return $token->getToken();
}
高级流
Azure Active Directory 的 授权码授权流 与其他流略有不同。您不指定作用域,而是指定要访问的资源 - 有一个参数 $provider->authWithResource
,它将自动将请求的 resource
参数填充为 $provider->resource
或 $provider->urlAPI
的值。此功能主要用于 Azure AD 的 v2.0 端点(更多内容请参见此处)。
使用自定义参数
从版本 1.3.0 开始,oauth2-client 允许指定授权 URL 的自定义参数,因此您现在可以使用如 prompt
、login_hint
等选项。以下是一个获取强制用户重新验证的授权 URL 的示例:
$authUrl = $provider->getAuthorizationUrl([
'prompt' => 'login'
]);
您可以在 此处 找到其他参数。
注销
如果您需要快速为用户生成注销 URL,可以执行以下操作
// Assuming you have provider properly initialized.
$post_logout_redirect_uri = 'https://www.msn.com'; // The logout destination after the user is logged out from their account.
$logoutUrl = $provider->getLogoutUrl($post_logout_redirect_uri);
header('Location: '.$logoutUrl); // Redirect the user to the generated URL
代表其他应用程序提供的令牌进行调用
// Use token provided by the other app
// Make sure the other app mentioned this app in the scope when requesting the token
$suppliedToken = '';
$provider = xxxxx;// Initialize provider
// Call this to get claims
// $claims = $provider->validateAccessToken($suppliedToken);
/** @var AccessToken $token */
$token = $provider->getAccessToken('jwt_bearer', [
'scope' => $provider->scope,
'assertion' => $suppliedToken,
'requested_token_use' => 'on_behalf_of',
]);
制作 API 请求
此库还提供了一个简单的界面,以简化与 Azure 图形 API 和 Microsoft 图形 的交互,以下方法可在 provider
对象上使用(它还处理在请求过程中需要时自动刷新令牌的流程):
get($ref, $accessToken, $headers = [])
post($ref, $body, $accessToken, $headers = [])
put($ref, $body, $accessToken, $headers = [])
delete($ref, $body, $accessToken, $headers = [])
patch($ref, $body, $accessToken, $headers = [])
getObjects($tenant, $ref, $accessToken, $headers = [])
这用于例如列出大量数据 - 需要列出所有用户等 - 它自动跟踪odata.nextLink
直到结束。$tenant
租户必须提供,因为odata.nextLink
不包含它。
request($method, $ref, $accessToken, $options = [])
有关用法,请参阅 #36。
请注意,如果您需要创建自定义请求,则还可以使用 getAuthenticatedRequest 和 getResponse 方法。
变量
$ref
URL 引用,不带开头的/
,例如myOrganization/groups
$body
请求的内容,可以是字符串(确保使用json_encode
进行编码)或者流(见Guzzle HTTP)$accessToken
通过使用getAccessToken
方法获得的访问令牌对象$headers
设置请求的自定义头(见Guzzle HTTP)
资源所有者
从1.1.0版本开始,资源所有者信息将由Azure Active Directory从传递给access_token
的JWT中解析。它暴露了一些属性和一个函数。
示例
$resourceOwner = $provider->getResourceOwner($token);
echo 'Hello, '.$resourceOwner->getFirstName().'!';
暴露的属性和函数包括
getId()
- 获取用户的对象id - 每个用户都是唯一的getFirstName()
- 获取用户的首名getLastName()
- 获取用户的姓或名getTenantId()
- 获取用户所属的租户的idgetUpn()
- 获取用户的用户主体名称,也可以用作用户的电子邮件地址claim($name)
- 从JWT中获取任何其他声明(指定为$name
),完整列表可以在这里找到这里
Microsoft Graph
使用此库调用Microsoft Graph非常简单。在提供程序初始化后,只需相应地更改API URL(将v1.0
替换为您希望使用的版本)
// Mention Microsoft Graph scope when initializing the provider
$baseGraphUri = $provider->getRootMicrosoftGraphUri(null);
$provider->scope = 'your scope ' . $baseGraphUri . '/User.Read';
// Call a query
$provider->get($provider->getRootMicrosoftGraphUri($token) . '/v1.0/me', $token);
之后,当请求访问令牌、刷新令牌等时,提供值为https://graph.microsoft.com/
的resource
,以便能够调用Graph(有关resource
的更多信息,请参阅这里)。
保护您的API - 实验性
从版本1.2.0开始,您现在可以使用此库通过Azure Active Directory身份验证轻松地保护您的API。提供程序现在还公开了validateAccessToken(string $token)
,允许您传递一个访问令牌,例如您在API的请求头中的Authorization
中接收到的。您可以使用以下方式使用此函数(在纯PHP中)
// Assuming you have already initialized the $provider
// Obtain the accessToken - in this case, we are getting it from Authorization header
$headers = getallheaders();
// Assuming you got the value of Authorization header as "Bearer [the_access_token]" we parse it
$authorization = explode(' ', $headers['Authorization']);
$accessToken = $authorization[1];
try {
$claims = $provider->validateAccessToken($accessToken);
} catch (Exception $e) {
// Something happened, handle the error
}
// The access token is valid, you can now proceed with your code. You can also access the $claims as defined in JWT - for example roles, group memberships etc.
您可能还需要从API访问其他资源(如Microsoft Graph)以获取更多信息。为此,有urn:ietf:params:oauth:grant-type:jwt-bearer
授权类型可用(见RFC)。示例(假设上面的代码正常工作,您已在Azure AD应用程序中正确配置了所需的权限)
$graphAccessToken = $provider->getAccessToken('jwt_bearer', [
'resource' => 'https://graph.microsoft.com/v1.0/',
'assertion' => $accessToken,
'requested_token_use' => 'on_behalf_of'
]);
$me = $provider->get('https://graph.microsoft.com/v1.0/me', $graphAccessToken);
print_r($me);
为了使您更容易记住整个grant_type
(urn:ietf:params:oauth:grant-type:jwt-bearer
)的名称,您只需使用简短的jwt_bearer
即可。
Azure Active Directory B2C - 实验性
您现在也可以非常简单地使用Azure Active Directory B2C。在身份验证之前,使用pathAuthorize
、pathToken
和scope
更改端点,并另外指定您的登录策略。请注意,B2C支持仍然是实验性的,尚未完全测试。
$provider->pathAuthorize = "/oauth2/v2.0/authorize";
$provider->pathToken = "/oauth2/v2.0/token";
$provider->scope = ["idtoken"];
// Specify custom policy in our authorization URL
$authUrl = $provider->getAuthorizationUrl([
'p' => 'b2c_1_siup'
]);
多用途刷新令牌 - 实验性
如果您需要访问多个资源(如您的API和Microsoft Graph),则可以使用多用途的刷新令牌。一旦为第一个资源获取了令牌,您只需像这样请求不同资源的另一个令牌
$accessToken2 = $provider->getAccessToken('refresh_token', [
'refresh_token' => $accessToken1->getRefreshToken(),
'resource' => 'http://urlOfYourSecondResource'
]);
目前有一个问题:当您调用API且令牌已过期时,它将具有$provider->urlAPI
的值,这对于$accessToken2
来说显然是错误的。解决方案很简单 - 将$provider->urlAPI
设置为要调用的资源。这个问题将在未来的版本中得到解决。请注意,这是实验性的,尚未完全测试。
已知用户
如果您正在使用此库并且希望在此列出,请告诉我们!
贡献
我们接受通过 Github上的拉取请求 的贡献。
致谢
- Jan Hajek (TheNetw.org)
- Vittorio Bertocci (Microsoft)
- 感谢在实现#16时提供的出色支持
- Martin Cetkovský (cetkovsky.eu]
- 所有贡献者
支持
如果您发现错误或遇到任何问题,或有关于此库的问题/疑问,请创建一个 新问题。
许可协议
MIT许可(MIT)。有关更多信息,请参阅 许可文件。