5分钟内为您的PHP应用添加身份验证功能
由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!
你是否曾经在开发应用时遇到过这样的情况:需要添加身份验证,却又苦于建立另一个用户名和密码数据库?本文将向你展示如何使用Okta在 5 分钟内轻松地为一个简单的 PHP 应用添加身份验证功能。通过利用 Okta 简洁的 OAuth API,我们可以轻松绕过用户身份验证的大部分难题,让 Okta 来处理那些繁琐的部分。
要学习本教程,您首先需要一个 Okta 开发者帐户。如果您还没有帐户,请免费注册,注册完成后再返回此处。为了简化操作,本示例不会使用任何外部 PHP 库或依赖项。
我们将首先使用一个简单的 PHP 文件来演示应用程序的登录/注销状态。然后,我们将集成Okta API来进行用户身份验证,并在用户登录后获取其用户名。您可以参考本指南,为自己的实际情况应用程序添加身份验证功能。
设置示例 PHP 应用程序
如果您想直接查看最终项目,请在 GitHub 上查看源代码。本文将逐步构建最终项目中的代码并进行讲解。
创建一个名为 `<filename>` 的新文件index.php,内容如下。这将根据用户是否已登录(PHP 会话中是否存在用户名)来设置应用程序的两种不同“视图”。
<?php
// Begin the PHP session so we have a place to store the username
session_start();
// If there is a username, they are logged in, and we'll show the logged-in view
if(isset($_SESSION['username'])) {
echo '<p>Logged in as</p>';
echo '<p>' . $_SESSION['username'] . '</p>';
echo '<p><a href="/?logout">Log Out</a></p>';
die();
}
// If there is no username, they are logged out, so show them the login link
if(!isset($_SESSION['username'])) {
$authorize_url = 'TODO';
echo '<p>Not logged in</p>';
echo '<p><a href="'.$authorize_url.'">Log In</a></p>';
}
有了这个简单的框架,我们就可以着手添加身份验证功能了。现在,这个应用会在会话变量中查找“用户名”,如果该变量存在,则认为该用户已登录。
接下来,我们添加一个简单的函数,用于向 Okta 发起 API 调用。该函数会发出一个 HTTP 请求并返回 JSON 解码后的响应。它接受一个 URL 和一个可选的参数数组。如果接受参数,则会发出一个 POST 请求,并将参数作为 HTTP 请求体。否则,它会向给定的 URL 发出一个 GET 请求。由于我们所有的 API 调用都会返回 JSON 响应体,因此该函数会对 JSON 响应进行解码,并返回解码后的对象。
function http($url, $params=false) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
if($params)
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
return json_decode(curl_exec($ch));
}
在 Okta 中创建 OAuth 应用程序
在继续之前,我们需要配置 Okta 开发者帐户,以获取用于与 API 通信的客户端 ID 和密钥。在 Okta 开发者帐户的“应用程序”部分,单击“添加应用程序”,然后选择“Web”http://localhost:8080/ 。由于我们将整个流程编写在这个 PHP 文件中,因此我们只需要更改默认应用程序设置中的回调 URL 。
点击“完成”,您将被带到下一个屏幕,您可以在此获取新的客户端 ID 和密钥。将这两个值复制到下面的变量中,并将此代码块添加到 PHP 文件顶部,紧跟在以下代码之后session_start():
$client_id = '';
$client_secret = '';
$redirect_uri = 'http://localhost:8080/';
我们还需要找到授权服务器的元数据 URL。从顶部菜单中,选择API ->授权服务器。您应该会在列表中看到一个授权服务器default。点击该服务器,然后复制客户端和重定向行下方的元数据 URI:
$metadata_url = 'https://{yourOktaOrg}/oauth2/default/.well-known/oauth-authorization-server';
// Fetch the authorization server metadata which contains a few URLs
// that we need later, such as the authorization and token endpoints
$metadata = http($metadata_url);
构建登录 URL
现在我们可以开始构建登录 URL 了,用户可以通过该 URL 进行身份验证。请将该行代码替换$authorize_url = 'TODO';为以下代码。
// Generate a random state parameter for CSRF security
$_SESSION['state'] = bin2hex(random_bytes(5));
// Build the authorization URL by starting with the authorization endpoint
// and adding a few query string parameters identifying this application
$authorize_url = $metadata->authorization_endpoint.'?'.http_build_query([
'response_type' => 'code',
'client_id' => $client_id,
'redirect_uri' => $redirect_uri,
'state' => $_SESSION['state'],
'scope' => 'openid',
]);
这段代码设置了 OAuth 授权码流程的初始阶段。如果您想了解有关这些参数的更多详细信息,我之前在本博客上写过一篇关于授权码流程的文章:什么是 OAuth 2.0 授权码授权类型?
现在我们已经搭建好了足够的环境来测试一下。从命令行导航到包含index.php文件的文件夹,然后启动一个 PHP 服务器:
php -S 127.0.0.1:8080
现在您可以在浏览器中访问此页面http://127.0.0.1:8080/,您将看到登录提示。
暂时不要点击链接,因为我们还需要设置回调处理和获取访问令牌。
处理 OAuth 重定向
当用户点击登录 URL 时,会被重定向到 Okta 授权服务器。授权服务器会要求用户登录(如果用户尚未登录),然后生成一个临时授权码并将用户重定向回此应用程序。为了验证用户是否确实已登录,应用程序需要通过在 Okta 授权服务器上使用该临时授权码来验证其有效性,以换取访问令牌。
在客户端 ID 配置行和呈现注销视图的部分之间,我们将添加一个新部分,用于处理将授权码交换为访问令牌。
我们先来添加一个检查查询字符串中授权码的功能。你的代码现在应该看起来像这样。
// ...
$metadata = http($metadata_url);
if(isset($_GET['code'])) {
// TODO: we'll work on filling out this section next
}
if(!isset($_SESSION['username'])) {
// ...
在这个新章节中,我们先用一些错误检查代码替换刚才添加的“TODO”注释。首先,我们要检查授权服务器返回的状态参数是否与用户开始登录时我们设置的参数一致。
if($_SESSION['state'] != $_GET['state']) {
die('Authorization server returned an invalid state parameter');
}
if(isset($_GET['error'])) {
die('Authorization server returned an error: '.htmlspecialchars($_GET['error']));
}
授权服务器也可能在此处返回错误,如果发生这种情况,我们将显示该错误。
接下来,我们需要从 URL 中获取授权码,并在令牌端点将其交换为访问令牌。为此,我们使用元数据响应中的令牌端点,并在 API 调用中包含我们的客户端 ID 和密钥:
$response = http($metadata->token_endpoint, [
'grant_type' => 'authorization_code',
'code' => $_GET['code'],
'redirect_uri' => $redirect_uri,
'client_id' => $client_id,
'client_secret' => $client_secret,
]);
if(!isset($response->access_token)) {
die('Error fetching access token');
}
如果一切顺利,我们最终会在$response对象中得到一个访问令牌。实际上,我们除了用来查找登录用户之外,并不需要这个访问令牌,因此我们不会将其存储在任何地方。相反,我们会使用它向令牌自省端点发出请求。
$token = http($metadata->introspection_endpoint, [
'token' => $response->access_token,
'client_id' => $client_id,
'client_secret' => $client_secret,
]);
if($token->active == 1) {
$_SESSION['username'] = $token->username;
header('Location: /');
die();
}
这段代码获取访问令牌,并将其与客户端凭据一起发送到令牌自省端点。自省端点会告知我们登录用户的用户名。如果令牌有效,我们会将用户名添加到会话中,然后重定向回首页。现在用户名已添加到会话中,我们的“应用程序”会认为用户已登录,并显示带有用户电子邮件地址的登录页面!
希望这个例子能帮助你了解如何轻松地为简单的 PHP 应用添加身份验证!当然,这只是一个极简示例,实际上你的应用功能更丰富,也可能组织得更好,包含多个文件。但你应该能够将这里学到的知识应用到你正在使用的其他框架或用例中!
您可以在GitHub上查看此应用程序的完整源代码。
延伸阅读
有关 OAuth 的更多信息和教程,请查看我们的其他博客文章!
- 什么是 OAuth 2.0 授权码授予类型?
- 什么是 OAuth 2.0 隐式授权类型?
- 使用 Symfony 4 和 Vue 构建一个基本的 CRUD 应用
- Spring Boot、OAuth 2.0 和 Okta 入门指南
和往常一样,我们非常乐意听到您对这篇文章或其他任何想法的反馈!请在评论区留言,或在推特上关注我们@oktadev!
文章来源:https://dev.to/oktadev/add-authentication-to-your-php-app-in-5-minutes-5e04


