misakstvanu/laravel-fortify-passkeys 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

misakstvanu/laravel-fortify-passkeys

Composer 安装命令:

composer require misakstvanu/laravel-fortify-passkeys

包简介

Passkeys backend implementation for Laravel Fortify

README 文档

README

Warning

This project is currently under development

Laravel Passkeys

This package provides a simple way to authenticate users using passkeys.

Authentication processes are based on web-auth/webauthn-lib package. On frontend, the opposite functionality is provided by @simplewebauthn/browser package.

Installation

  1. Install the package via composer:
composer require misakstvanu/laravel-fortify-passkeys
  1. Service provider will be auto discovered. If you want to register it manually, add the following line to your config/app.php
'providers' => [
    /*
     * Package Service Providers...
     */
    // ...
    Misakstvanu\LaravelFortifyPasskeys\PasskeysServiceProvider::class,
];
  1. Publish migration to create passkeys table:
php artisan vendor:publish --tag=laravel-fortify-passkeys-migrations
php artisan migrate
  1. (optional) Publish the config file:
php artisan vendor:publish --tag=laravel-fortify-passkeys-config

Configuration

  1. Implement an interface Misakstvanu\LaravelFortifyPasskeys\Contracts\PasskeyAuthentication on your User model:
use Misakstvanu\LaravelFortifyPasskeys\Models\Contracts\PasskeyAuthentication;

class User extends Authenticatable implements PasskeyAuthentication {
    // ...
}
  1. Set up passkeys relation on your User model:
use Misakstvanu\LaravelFortifyPasskeys\Models\Passkey;

public function passkeys() :HasMany {
    return $this->hasMany(Passkey::class);
}
  1. Once you have published the config file, you can configure the package by editing the config/passkeys.php file. The variables are:
  • user_model - the model that will be used to authenticate the user. Default: App\Models\User
  • route_prefix - prefix for the 4 routes this package loads. Default: passkeys
  • route_middleware - middleware that will be applied to the routes. Default: ['web']
  • username_column - the column that will be used to find the user. Default: email
  • relying_party_ids - an array of domains that will be allowed insecure connection, use with caution. Default: []
  • registration_user_validation - validation rules that will be applied to the request when registering new user. These values will then be persisted with the new user. Default: []

Setting Environment Variables

To make the configuration more flexible, you can set the configuration values using environment variables. Here are the environment variables you can set:

  • PASSKEYS_USER_MODEL - the model that will be used to authenticate the user. Default: App\Models\User
  • PASSKEYS_ROUTE_PREFIX - prefix for the 4 routes this package loads. Default: passkeys
  • PASSKEYS_ROUTE_MIDDLEWARE - middleware that will be applied to the routes. Default: web
  • PASSKEYS_USERNAME_COLUMN - the column that will be used to find the user. Default: email
  • PASSKEYS_RELYING_PARTY_IDS - a comma-separated list of domains that will be allowed insecure connection, use with caution. Default: ``
  • PASSKEYS_REGISTRATION_USER_VALIDATION - a comma-separated list of validation rules that will be applied to the request when registering new user. Default: ``

Examples

Here are some examples of how to set the environment variables in your .env file:

PASSKEYS_USER_MODEL="App\Models\User"
PASSKEYS_ROUTE_PREFIX="passkeys"
PASSKEYS_ROUTE_MIDDLEWARE="web,auth"
PASSKEYS_USERNAME_COLUMN="email"
PASSKEYS_RELYING_PARTY_IDS="example.com,another-example.com"
PASSKEYS_REGISTRATION_USER_VALIDATION="required|string|max:255"

Usage

There are now 6 named routes that make everything work:

POST 'passkeys.login.start' - login route, accepts email or other field specified in your config. If a user with the given username/email exists and has a passkey registered, credential request options will be returned. If the user does not exist, HTTP 404 will be returned instead.

POST 'passkeys.login.verify' - login route, accepts passkey response. If the passkey authentication passes, the user will be logged in. If the passkey authentication fails, an exception with additional information is thrown.

POST 'passkeys.register.start' - registration route, accepts email or other field specified in your config. Credential request options is returned.

POST 'passkeys.register.verify' - registration route, accepts passkey response. If the passkey registration passes, an account will be created from the username/email and any additional data specified in config and sent along with this request. If the passkey registration fails, an exception with additional information is thrown.

POST 'passkeys.add.options' - add passkey route, generates options to add a new passkey to a logged-in user.

POST 'passkeys.add' - add passkey route, accepts passkey response. If the passkey registration passes, the passkey will be added to the existing account. If the passkey registration fails, an exception with additional information is thrown.

JS Example

Below is minimal example of how to use this package with js @simplewebauthn/browser.

import {browserSupportsWebAuthn, startAuthentication, startRegistration} from "@simplewebauthn/browser";
//import 'api' object based on axios and configured with our app url

function base64ToArrayBuffer(base64) {
    const binaryString = atob(base64)
    const len = binaryString.length
    const bytes = new Uint8Array(len)
    for (let i = 0; i < len; i++) {
        bytes[i] = binaryString.charCodeAt(i)
    }
    return bytes.buffer
}
function register() {
    // Ask for the authentication options
    api.post('/passkey/register/options', {
        email: 'your@email.com',
    })
        // Prompt the user to create a passkey
        .then((response) => {
            // Decode the challenge before passing to startRegistration
            if (response.data.challenge) {
                response.data.challenge = base64ToArrayBuffer(response.data.challenge)
            }
            startRegistration(response.data)
        })
        // Verify the data with the server
        .then((attResp) => api.post('/passkey/register', attResp))
        .then((verificationResponse) => {
            if (verificationResponse.data?.verified) {
                // WE ARE REGISTERED AND LOGGED IN / PASSKEY WAS ASSOCIATED WITH NEW OR LOGGED IN ACCOUNT
                return window.location.reload();
            }
            // Something went wrong verifying the registration.
        })
        .catch((error) => {
            // Handle error information
        });
}
function login() {
    // Ask for the authentication options
    api.post('/passkey/login/options', {
            email: 'your@email.com',
        })
        // Prompt the user to authenticate with their passkey
        .then((response) => {
            // Decode the challenge before passing to startRegistration
            if (response.data.challenge) {
                response.data.challenge = base64ToArrayBuffer(response.data.challenge)
            }
            startAuthentication(response.data)
        })
        // Verify the data with the server
        .then((attResp) =>
            api.post('/passkey/login', attResp),
        )
        .then((verificationResponse) => {
            if (verificationResponse.data?.verified) {
                // WE ARE LOGGED IN
                return window.location.reload();
            }
            // Something went wrong verifying the authentication.
        })
        .catch((error) => {
            // Handle error information
        });
}
function addPasskey() {
    // Ask for the options to add a new passkey
    api.post('/passkey/add/options')
        // Prompt the user to create a passkey
        .then((response) => startRegistration(response.data))
        // Verify the data with the server
        .then((attResp) => api.post('/passkey/add', attResp))
        .then((verificationResponse) => {
            if (verificationResponse.data?.verified) {
                // PASSKEY WAS ADDED TO THE EXISTING ACCOUNT
                return window.location.reload();
            }
            // Something went wrong verifying the registration.
        })
        .catch((error) => {
            // Handle error information
        });
}

Refactoring

The code has been refactored to reduce duplication and follow Laravel best practices. A new service class PasskeyService has been created to handle common logic for generating options and verifying responses. The generateOptions and verify methods in AddPasskeyController, RegistrationController, and AuthenticationController have been refactored to use PasskeyService.

PasskeyService

The PasskeyService class is located in src/Services/PasskeyService.php. It contains the following methods:

  • generateOptions(Request $request, $user = null): array - Generates options for passkey creation.
  • verify(Request $request, ServerRequestInterface $serverRequest, $user = null): array - Verifies the passkey response.

Controllers

The generateOptions and verify methods in the following controllers have been refactored to use PasskeyService:

  • AddPasskeyController
  • RegistrationController
  • AuthenticationController

The PasskeyService is injected into the constructors of these controllers and used to handle the common logic for generating options and verifying responses.

Response Array

The response has been updated to return an array with "verified". This change has been applied to the verify methods in the AddPasskeyController, RegistrationController, and AuthenticationController. The updated response is as follows:

if ($response['verified']) {
    return ['verified' => true];
}

return ['verified' => false];

misakstvanu/laravel-fortify-passkeys 适用场景与选型建议

misakstvanu/laravel-fortify-passkeys 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 52 次下载、GitHub Stars 达 22, 最近一次更新时间为 2024 年 02 月 13 日, 在 PHP 生态内属于活跃度较高的组件。

我们在过去多个企业项目中使用过 misakstvanu/laravel-fortify-passkeys 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 misakstvanu/laravel-fortify-passkeys 我们能提供哪些服务?
定制开发 / 二次开发

基于 misakstvanu/laravel-fortify-passkeys 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 52
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 22
  • 点击次数: 17
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 22
  • Watchers: 3
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2024-02-13