Passkeys是Web身份验证的新标准登录方法,但到目前为止,很少有开发人员教程显示如何在代码级别上添加它们。
在以下内容中,我们将使用Corbado的Web组件将PHP Symfony应用程序的基于密码的登录名更改为无密码的,Passkey-Fort的身份验证。
Web组件是一个易于集成的,轻巧的身份验证层,并具有出色的开箱即用的Passkey UX。
设置
vincentdelitz / tutorial-passkeys-php-symfony-webcomponent
完整的教程,用于使用PHP Symfony集成Corbado Web组件,用于Passkey-Fir-First验证。
Complete integration sample for the Corbado web component
This is a sample implementation of frontend and backend where the Corbado web component is integrated.
Note: In this tutorial a customer system is created with some pre-existing password-based users. Have a look at our docs,如果您没有任何用户,请查看集成。
1.文件结构
如果您
让我们先获取整个图片!我们使用带有三个容器的Dockerized设置:
- 第一个容器运行我们的PHP Symfony应用程序
- 第二个容器与现有用户托管数据库。
- 第三个容器运行phpmyadmin,可轻松访问数据库
我们的文件夹结构看起来像这样
├── ...
├── config
| └── services.yaml # Service configurations
├── src
│ ├── Controller
│ │ ├── WebhookController.php # Manages endpoints for webhook
│ └── └── AppController.php # Manages endpoints for application
├── templates
│ ├── home.html.twig # Home page which you only get to see if you are logged in
│ ├── login.html.twig # Login page which contains the Corbado web component; Acts as landing page if you are not logged in
├── .env # Contains all Symfony environment variables
└── ...
使用docker compose up
启动系统。
我们的前端在http://localhost:8000上运行,而我们的后端可在http://localhost:8000/api上找到。
我们的登录页面看起来像这样:
要集成Corbado Web组件,我们按照以下步骤进行操作:
- Create project in the Corbado developer panel
- Integrate web component in the frontend
- Create backend endpoint to generate a session
- (Optional) Enable password-based login as fallback
- (Optional) Make your local application reachable for Corbado via Corbado CLI
1.在Corbado开发人员面板中创建项目
我们从前往Corbado developer panel并创建一个帐户开始。我们受到此屏幕的欢迎
我们单击“集成指南”以逐步完成所有操作。
我们想使用“ Web组件”,所以这就是我们选择的。
另外,我们有一个具有现有用户群的系统,因此我们单击“是”。之后,我们发现自己处于开发人员面板的概述(如果是您的第一次,则需要通过电子邮件确认您的帐户)。
前往“集成指南”。这引导我们完成了整合工作所需的所有步骤。
在步骤1中,我们创建一个API秘密。稍后,我们需要项目ID和生成的API秘密,以便与Corbado的API通信。另外,我们需要配置我们的授权来源。授权的来源是从集成了Web组件的站点的浏览器URL(与协议和端口,但没有路径)。我们需要CORS(交叉启用请求共享)和对其进行约束的Passkeys。在我们的情况下,我们将其发送到http://localhost:8000。
在第二个可选步骤中,我们配置了Webhook。这是需要的,因此Corbado可以与我们的后端进行交流,例如检查现有用户匹配的用户名和密码。稍后有关的更多详细信息。
我们稍后将使用p36qlbyrvhozdtâ和``Z9asidcu2xlyou作为凭据设置了我们的Webhook,yound.p36qlbyrvhozdt-
在步骤3中,我们添加了应用程序URL并重定向URL。应用程序URL是Web组件运行的前端中的URL。例如,它在单击电子邮件魔术链接后再次将用户转发到Web组件。
重定向URL是在Corbado成功身份验证用户后,可以接收Corbado的会话令牌作为GET参数,因此可以启动会话。我们稍后在http://localhost:8000/redirect上实施重定向URL,但是我们可以在这里输入。
那样,该项目已建立!
2.将Corbado Web组件集成到前端
现在我们已经完成了Corbado设置,让我们开始编码!在前端,我们将Corbado Web组件集成到我们的登录页面中。添加以下内容,在HTML头部代码,因此它提前加载JavaScript:
<script defer src="https://auth.corbado.com/auth.js"></script>
之后,我们将当前登录表替换为Corbado的登录表(当然使用您自己的项目ID):
<corbado-auth project_id="<project ID>" conditional="yes">
<input name="username" id="corbado-username" value="" required autocomplete="webauthn" autofocus/>
</corbado-auth>
浏览浏览器中我们的登录页面,显示了Corbado Web组件:
提示:如果您现在输入您的电子邮件地址并尝试注册或登录,则将收到一条错误消息。那是因为我们还没有配置后端。
3.创建后端端点以生成会话
一旦用户通过前端的Corbado Web组件成功身份验证,他将使用CorbadoSessionToken GET参数发送到重定向URL。我们将此重定向的URL配置为http://localhost:8000/redirect,还记得吗?我们现在实现此端点。
我们将在services.yaml文件中初始化corbado api客户端。为此,我们需要上面的项目ID和API秘密。
services:
Corbado\Client:
autowire: true
bind:
$baseURI: 'https://api.corbado.com'
$username: '%app.projectID%'
$password: '%app.apiSecret%'
我们在我们的RouteConfig中为所需端点添加了一条路由(通过我们的框架中的注释)。
#[Route(‘/api/redirect, name: success, methods: ‘GET’)]
在重定向端点中,我们读取了CorbadoSessionToken查询参数的值。然后,我们使用Corbado PHP SDK致电Corbado的SessionVerify API端点,这将为我们提供令牌所属用户的电子邮件和名称。
Public function redirect(UserRepository $userRepo, Request $request, SessionInterface $session, Client $apiClient): Response {
$token = $request->query->get(‘corbadoSessionToken’);
$useragent = $request->headers->get(‘User-Agent’);
$remoteAddress = $request->server->get(‘REMOTE_ADDR’);
try {
$result = $apiClient->widget()->sessionVerify($token,
$remoteAddress, $useragent);
} catch (\Exception $e) {
return new Response(‘Session token expired’, 400);
}
$response = $result->getData()->getUserData(); // Parse json response from Corbado request
$userData = json_decode($response, true); $username =
$userData[‘username’];
$userFullName = $userData[‘userFullName’]; // Create user if not exists
$user = $userRepo->findOneBy([‘email’ => $username]);
if ($user === null) {
$user = new User($userFullName, $username);
$userRepo->save($user, true);
}
$session->set(“userID”, $user->getId()); // Forward the user to frontend page
return $this->redirectToRoute(‘home’);
}
我们现在知道谁只是登录我们的应用程序。我们为用户创建会话,然后将他重定向到应用程序的登录页面:
如果您没有现有的用户群,那么将无密码,Passkey-First身份验证与Corbado!
集成所需的全部4.(可选)启用基于密码的登录作为后备
我们不想锁定现有用户,因此我们将基于密码的身份验证作为后备。因此,Corbado需要与我们的后端进行交流。它通过我们后端设置的Webhook来做到这一点。在以前的步骤中,我们将Webhook URL设置为http://localhost:8000/corbado-webhook及其凭证为webhookusernameâ和webhookpassword。
Corbado提供了一些PHP代码,有助于添加Webhooks:
composer require corbado/webhook-php
然后,我们将Webhook的用户名和密码添加到我们的PHP Symfony环境变量中,以便当我们想对传入的Webhook调用:
进行身份验证时,它们可用
WEBHOOK_USERNAME=p36qLbyRvHoZDT
WEBHOOK_PASSWORD=z9aSidcu2xLyoU
现在我们为Webhook创建了一个路线:
# -------- Webhook --------
corbado:
path: /corbado-webhook
controller: App\Controller\WebhookController::corbado_webhook
以及使Webhook可用的控制器。
Webhook Controller使用先前安装的Corbado Webhook库以及我们通过HTTP Basic Auth受保护的路线。
class WebhookController extends AbstractController
{
#[Route('/corbado-webhook', name: 'corbado', methods: 'POST')]
public function corbadoWebhook(UserRepository $userRepo, Request $request, string $webhookUsername, string $webhookPassword): Response
{
try {
// Create new webhook instance with "webhookUsername" and "webhookPassword". Both must be
// set in the developer panel (https://app.corbado.com) and are used to secure your
// webhook (this one here) with basic authentication.
$webhook = new Webhook($webhookUsername, $webhookPassword);
// Handle authentication so your webhook is secured (basic authentication). If username
// and/or password are invalid handleAuthentication() will send HTTP status code
// 401 (Unauthorized) and terminate/exit execution here. $webhook->handleAuthentication();
如果用户在Web组件中输入电子邮件,我们刚刚安装的Webhook会接到电话。 corbado_webhook
函数将处理它,从而导致kude4函数的呼叫。如果用户存在,这意味着他已经有了密码,Corbado可以选择通过密码登录。
function userStatus(UserRepository $userRepo, string $username): string
{
$user = $userRepo->findOneBy(['email' => $username]);
//Look up in database if $username exists and if $username is blocked/not permitted to login
if ($user == null) {
return AuthMethodsDataResponse::USER_NOT_EXISTS;
} if ($user->isBlocked()) {
return AuthMethodsDataResponse::USER_BLOCKED;
}
return AuthMethodsDataResponse::USER_EXISTS;
}
用户输入密码后,发出了另一个Webhook调用,从而导致呼叫verifyPassword
函数。在那里,我们检查给定凭证是否匹配并将响应发送回响应。
/**
* Verify given username and password.
* @param UserRepository $userRepo
* @param string $username
* @param string $password
* @return bool */
private function verifyPassword(UserRepository $userRepo, string $username, string $password): bool
{
$user = $userRepo->findOneBy(['email' => $username]);
if ($user == null || $user->getPassword() == null) {
return false;
}
return password_verify($password, $user->getPassword());
}
完成!现在,我们所有的用户都可以使用PassKey,而现有的用户将密码作为后备选项。
但是,等等,如果我们的后端仅在本地运行,尤其是在开发过程中,Corbado如何调用端点?
5.通过Corbado CLI使您的本地申请可用于Corbado
使用Corbado CLI,我们为外界创建了本地应用程序的隧道,以便可以调用Webhook URL。我们通过遵循docs
来安装它启动后,在我们的机器上运行的网络钩从Corbado到我们本地实例。类似于上图,然后该过程如下:
- 浏览器请求我们的登录页面
- appController将包含Web组件的HTML页面发送回HTML页面。
- 用户输入电子邮件地址后,Web组件将其发送给Corbado。
- Corbado对其进行处理,并向我们的Webhook发送请求以检查用户是否存在。
- 该消息通过Corbado CLI转发,以达到我们的本地实例。 (如果您的解决方案正在生产中,Corbado可以直接致电Webhook Controller而无需Corbado Cli隧道,因为您会有一个公共地址)。
- 我们的Webhook控制器发送了请求的信息。
- 该消息再次通过Corbado Cli转发
- Corbado告诉Web组件如何做出反应(例如,向用户询问密码)。
之后,我们前往Corbado developer panel复制我们的CLI秘密。
我们使用项目ID和CLI秘密登录:
corbado login --projectID pro-1987097639455463555 --cliSecret 4uKn...
登录后,我们可以使用subscribe命令启动隧道(随着我们的Symfony应用程序在此处运行时,使用端口8000)。
corbado subscribe http://localhost:8000 --projectID pro-1987097639455463555 --cliSecret 4uKn...
现在,我们可以测试我们的Webhook是否可以通过进入https://app.corbado.com/app/settings/webhooks/testing,填写存根数据并运行测试。如果一切顺利,所有测试都将通过。
如果我们现在转到http://localhost:8000/login并输入已经存在的帐户的电子邮件,则Web组件应询问您的密码(如果尚未创建该帐户的Passkey)。
之后,要求用户为将来的登录创建一个Passkey。