jbtronics/2fa-webauthn
Composer 安装命令:
composer require jbtronics/2fa-webauthn
包简介
Webauthn Two-Factor-Authentication Plugin for scheb/2fa
README 文档
README
This repository contains a plugin for scheb/2fa that adds support for Webauthn authenticators (like a Yubikey) as a second factor.
Features
- Support of all webauthn authenticators as second factor
- Supports multiple authenticators per user
- Backward compatibility for existing registered U2F keys (from r/u2f-two-factor-bundle)
Requirements
- Symfony 7
- PHP 8.2 or later
- webauthn/webauthn-lib 5.0 or later
If you want to use symfony 5.* and PHP 7.4, use the version 1.0.0 of this bundle. If you want to use PHP 8.1 and webauthn/webauthn-lib 4.*, use the version 2.0.0 of this bundle.
Installation
- Install the bundle
composer require jbtronics/2fa-webauthn - Enable the bundle in your
config/bundles.php(normally done by Symfony flex automatically) - If you want to use the easy doctrine integration, add the web-authn symfony bundle:
composer require web-auth/webauthn-symfony-bundle. You do not need to run the community recipe, as we just use the doctrine type definitons from the bundle. AddWebauthn\Bundle\WebauthnBundle::class => ['all' => true],to yourconfig/bundles.phpinstead.
Setup and Usage
After following the Installation steps, do the follwing steps to setup the library:
- Add
Jbtronics\TFAWebauthn\Model\TwoFactorInterfaceinterface to your user entity:
use Jbtronics\TFAWebauthn\Model\TwoFactorInterface as WebauthnTwoFactorInterface; class User implements WebauthnTwoFactorInterface { /** * @var Collection<int, PublicKeyCredentialSource> * @ORM\OneToMany(targetEntity="App\Entity\WebauthnKey", mappedBy="user", cascade={"REMOVE"}, orphanRemoval=true) */ private $webauthnKeys; /** * Determines whether the user has 2FA using Webauthn enabled * @return bool True if the webauthn 2FA is enabled, false otherwise */ public function isWebAuthnAuthenticatorEnabled(): bool { //Return true to enable webauthn 2FA return count($this->webauthnKeys) > 0; } /** * Returns a list of all legacy U2F keys, associated with this user * Return an empty array, if this user does not have any legacy U2F keys. * @return iterable<LegacyU2FKeyInterface> */ public function getLegacyU2FKeys(): iterable { return []; //If you have no legacy U2F keys, return just an empty array //return $this->u2f_keys; //Otherwise return the legacy keys (see migration section below) } /** * Returns a list of all webauthn keys, associated with this user * @return iterable<PublicKeyCredentialSource> */ public function getWebauthnKeys(): iterable { return $this->webauthnKeys; } /** * Returns the webauthn user entity that should be used for this user. * @return PublicKeyCredentialUserEntity */ public function getWebAuthnUser(): PublicKeyCredentialUserEntity { //Return webauthn user definition for this user. As we just use it as an two-factor authentication, the values here are most likely not that important return new PublicKeyCredentialUserEntity( $this->getUsername(), // The Webauthn Name (like a username) $this->getID(), // A unique identifier for this user $this->getDisplayName() // The display name of this user (optional, otherwise null) ); } }
- Create a new entity for the webauthn keys. For simplicity we use the templates from the web-auth/webauthn-symfony-bundle (see here for more infos)
declare(strict_types=1); namespace App\Entity; use Doctrine\ORM\Mapping as ORM; use Webauthn\PublicKeyCredentialSource as BasePublicKeyCredentialSource; #[ORM\Entity] #[ORM\Table(name: 'webauthn_keys')] class WebAuthnKey extends BasePublicKeyCredentialSource { #[ORM\Id] #[ORM\Column(type: Types::INTEGER)] #[ORM\GeneratedValue] private $id; #[ORM\ManyToOne(targetEntity: User::class, inversedBy: 'webauthn_keys')] protected ?User $user = null; //You can declare additional fields too, if you want to store additional information about the key (like a name) private $name; public function getId(): string { return $this->id; } public static function fromRegistration(BasePublicKeyCredentialSource $registration): self { return new self( publicKeyCredentialId: $registration->publicKeyCredentialId, type: $registration->type, transports: $registration->transports, attestationType: $registration->attestationType, trustPath: $registration->trustPath, aaguid: $registration->aaguid, credentialPublicKey: $registration->credentialPublicKey, userHandle: $registration->userHandle, counter: $registration->counter, otherUI: $registration->otherUI, backupEligible: $registration->backupEligible, backupStatus: $registration->backupStatus, uvInitialized: $registration->uvInitialized, ); } }
-
Include javascript frontend code into your project: For webauthn we need some javascript code to interact with the authenticators. Copy the file from
assets/tfa_webauthn.jsto your project and include it either by loading it via a<script>tag or by including it in your webpack using.addEntry(). -
Add configuration file
config/packages/jbtronics_2fa_webauthn.yaml:
tfa_webauthn: enabled: true # Optional configuration options: # timeout: 60000 # The timeout in millisceconds to allow the user to interact with the authenticator. Default: 60000 # template: '' # The template to use for the login form # rpID: null # The relying party ID of your application. If null, the current host will be used. Default: null # U2FAppID: null # The U2F AppID of your application. If null, the current host will be used. Default: null # These settings are most likely not important for two-factor authentication: # rpName: 'My Application' # The relying party name of your application, Default: 'My Application' # rpIcon: null # The relying party icon of your application. Default: null
- Customize the login template: Similar to the base login template of the
scheb/2fabundle you will most likely need to override the login template of this bundle to integrate it into your design. Copy the template fromResources/views/Authentication/form.html.twigto your project and customize it to your needs. Configure thetemplatesetting in the bundle config to your new path.
Registration of new keys
In principle the login with exsting keys should work now, but you will most likely need some possibility to register new keys. To make this easy there is the Jbtronics\TFAWebauthn\Services\TFAWebauthnRegistrationHelper service to help you with this:
- Create a new controller, which will handle the registration, which should looks like this:
use Jbtronics\TFAWebauthn\Services\TFAWebauthnRegistrationHelper;Ä class WebauthnKeyRegistrationController extends AbstractController { /** * @Route("/webauthn/register", name="webauthn_register") */ public function register(Request $request, TFAWebauthnRegistrationHelper $registrationHelper, EntityManagerInterface $em) { //If form was submitted, check the auth response if ($request->getMethod() === 'POST') { $webauthnResponse = $request->request->get('_auth_code'); //Retrieve other data from the form, that you want to store with the key $keyName = $request->request->get('keyName'); try { //Check the response $new_key = $registrationHelper->checkRegistrationResponse($webauthnResponse); } catch (Exception $exception) { // Handle errors... } //If we got here, the registration was successful. Now we can store the new key in the database //Convert our returned key into an database entity and persist it... $keyEntity = WebauthnKey::fromRegistration($new_key); $keyEntity->setName($keyName); $keyEntity->setUser($this->getUser()); $em->persist($keyEntity); $em->flush(); $this->addFlash('success', 'Key registered successfully'); //We are finished here so return to another page return $this->redirectToRoute('homepage'); } return $this->render( 'webauthn_register.html.twig', [ //Generate the registration request 'registrationRequest' => $registrationHelper->generateRegistrationRequestAsJSON(), ] ); } }
- Create a template with a form, which will be used to register the new key. The form should look like this:
<form method="post" class="form" action="{{ path('webauthn_register') }}" data-webauthn-tfa-action="register" data-webauthn-tfa-data='{{ registrationRequest|raw }}'> <input type="text" name="keyName" id="keyName" placeholder="Shown key name"/> <button type="submit" class="btn btn-success">Add new Key</button> <input type="hidden" name="_auth_code" id="_auth_code" /> </form>
The data-webauthn-tfa-action attribute marks the form as webauthn registration form and is handled by the frontend code included above.
If the form is submitted, the frontend code will catch that and start a registration process. The response is put it into the hidden input field with the id _auth_code and sent to our controller for parsing.
Migrate from r/u2f-two-factor-bundle
- Replace the
R\U2FTwoFactorBundle\Model\U2F\TwoFactorKeyInterfaceinterface of your U2FKey entity withJbtronics\TFAWebauthn\Model\LegacyU2FKeyInterfaceand remove the fromRegistrationData() function (as we do not need it anymore). - Replace the
R\U2FTwoFactorBundle\Model\U2F\TwoFactorInterfaceinterface of your user withJbtronics\TFAWebauthn\Model\TwoFactorInterface, configure it (see above) and replace/rename yourgetU2FKeys()function togetLegacyU2FKeys(). - (Optional:) If your appID is not the same as your domain, configure it with the
U2FAppIDoption. But this should normally not be needed - Remove the old routes, templates and settings of the
r/u2f-two-factor-bundleand remove it from your application - Follow the setup steps above
License
This bundle is licensed under the MIT license. See LICENSE for details.
Credits
- Webauthn support is provided by spomky-labs webauthn-framework
- This library is inspired by the r/u2f-two-factor-bundle bundle
jbtronics/2fa-webauthn 适用场景与选型建议
jbtronics/2fa-webauthn 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 55.42k 次下载、GitHub Stars 达 15, 最近一次更新时间为 2022 年 10 月 03 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「symfony」 「2fa」 「symfony-bundle」 「two-factor-authentication」 「webauthn」 「scheb-2fa」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 jbtronics/2fa-webauthn 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 jbtronics/2fa-webauthn 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 jbtronics/2fa-webauthn 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Laravel Authentication package with built-in two-factor (Authy) and social authentication (Socialite).
This package provides Laravel bindings and a Eloquent/Model trait for pragmarx/recovery package.
The bundle for easy using json-rpc api on your project
Symfony bundle for the Rekapager library
Symfony bundle for Cloudflare integration: trusted proxies, real client IP detection, forwarded headers.
Bundle Symfony DaplosBundle
统计信息
- 总下载量: 55.42k
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 15
- 点击次数: 21
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2022-10-03