laravel-scan-login maintained by wuwx
Laravel Scan Login
一个基于 QR 码的 Laravel 扫码登录包,允许用户通过手机扫描二维码快速登录桌面应用。
功能特性
- 🔐 安全的扫码登录:使用状态机管理登录流程
- 📱 移动端确认:手机扫码后在移动端确认登录
- ⚡ 实时状态同步:实时更新登录状态
- 🎨 现代化 UI:响应式界面设计
- 🛡️ 安全防护:Token 自动过期,防止重放攻击
安装
1. 安装包
composer require wuwx/laravel-scan-login
2. 发布配置文件
php artisan vendor:publish --provider="Wuwx\LaravelScanLogin\ScanLoginServiceProvider"
3. 配置环境变量
在 .env 文件中添加以下配置(可选):
# Token 过期时间(分钟,默认:5)
SCAN_LOGIN_TOKEN_EXPIRY_MINUTES=5
# QR 码大小(像素,默认:200)
SCAN_LOGIN_QR_CODE_SIZE=200
# QR 码格式(svg 或 png,默认:svg)
SCAN_LOGIN_QR_CODE_FORMAT=svg
# QR 码错误纠正级别(low, medium, quartile, high)
SCAN_LOGIN_QR_CODE_ERROR_CORRECTION=high
# QR 码颜色
SCAN_LOGIN_QR_CODE_FOREGROUND=#000000
SCAN_LOGIN_QR_CODE_BACKGROUND=#ffffff
# 登录成功后的重定向地址(默认:/)
SCAN_LOGIN_SUCCESS_REDIRECT=/dashboard
# 状态轮询间隔(秒,默认:3)
SCAN_LOGIN_POLLING_INTERVAL=3
# Token 长度(字符数,默认:64)
SCAN_LOGIN_TOKEN_LENGTH=64
# 启用/禁用扫码登录功能(默认:true)
SCAN_LOGIN_ENABLED=true
# 启用/禁用 GeoIP 地理位置显示(默认:true)
SCAN_LOGIN_ENABLE_GEOIP=true
4. 配置 GeoIP(可选)
本包使用 torann/geoip 来显示登录地理位置信息。首先发布 GeoIP 配置文件:
php artisan vendor:publish --provider="Torann\GeoIP\GeoIPServiceProvider" --tag=config
然后更新 GeoIP 数据库:
php artisan geoip:update
如果不需要地理位置功能,可以在 .env 中设置:
SCAN_LOGIN_ENABLE_GEOIP=false
5. 运行迁移
php artisan migrate
使用方法
安装完成后,包会自动注册路由:
/scan-login- 桌面端二维码登录页面/scan-login/{token}- 移动端确认登录页面
基本使用
- 桌面端:用户访问
/scan-login页面,系统会显示二维码 - 移动端:用户扫描二维码后,会跳转到确认页面
- 确认登录:用户在移动端确认后,桌面端自动完成登录
登录流程
1. 桌面端流程
- 用户访问扫码登录页面
- 系统生成 QR 码,包含登录链接
- 用户使用手机扫描 QR 码
- 系统轮询检查登录状态
- 登录成功后自动跳转
2. 移动端流程
- 用户扫描 QR 码
- 跳转到移动端确认页面(需要登录)
- 显示登录设备信息
- 用户确认或取消登录
- 桌面端自动完成登录
自定义视图
发布视图文件
php artisan vendor:publish --provider="Wuwx\LaravelScanLogin\ScanLoginServiceProvider" --tag="views"
视图文件位于 resources/views/vendor/scan-login/:
livewire/pages/qr-code-login-page.blade.php- 桌面端二维码页面livewire/pages/mobile-login-confirm-page.blade.php- 移动端确认页面
事件系统
本包提供了完整的事件系统,允许你在登录流程的各个阶段执行自定义逻辑。
可用事件
ScanLoginTokenCreated- Token 创建时触发ScanLoginTokenClaimed- 二维码被扫描时触发ScanLoginTokenConsumed- 登录成功时触发ScanLoginTokenCancelled- 用户取消登录时触发ScanLoginTokenExpired- Token 过期时触发
监听事件示例
在 app/Providers/EventServiceProvider.php 中注册监听器:
use Wuwx\LaravelScanLogin\Events\ScanLoginTokenConsumed;
use App\Listeners\SendLoginNotification;
protected $listen = [
ScanLoginTokenConsumed::class => [
SendLoginNotification::class,
],
];
创建监听器:
<?php
namespace App\Listeners;
use Wuwx\LaravelScanLogin\Events\ScanLoginTokenConsumed;
class SendLoginNotification
{
public function handle(ScanLoginTokenConsumed $event): void
{
$user = \App\Models\User::find($event->consumerId);
// 发送登录通知
$user->notify(new \App\Notifications\ScanLoginSuccess($event->token));
}
}
详细文档请参考 EVENTS.md。
维护命令
清理过期 Token
定期清理过期的 token 以保持数据库整洁:
# 删除 7 天前的 token(默认)
php artisan scan-login:cleanup
# 删除 30 天前的 token
php artisan scan-login:cleanup --days=30
# 只删除特定状态的 token
php artisan scan-login:cleanup --status=expired
# 预览将要删除的 token(不实际删除)
php artisan scan-login:cleanup --dry-run
# 强制删除,不需要确认
php artisan scan-login:cleanup --force
查看统计信息
查看 token 使用统计:
# 查看最近 30 天的统计(默认)
php artisan scan-login:stats
# 查看最近 7 天的统计
php artisan scan-login:stats --days=7
自动清理
建议在调度任务中添加自动清理:
// app/Console/Kernel.php
protected function schedule(Schedule $schedule)
{
// 每天清理 7 天前的 token
$schedule->command('scan-login:cleanup --force')->daily();
// 每月更新 GeoIP 数据库
$schedule->command('geoip:update')->monthly();
}
安全考虑
- Token 过期:Token 默认 5 分钟后过期
- 状态验证:严格的状态转换规则
- 设备信息记录:记录 IP 地址和用户代理
- 地理位置显示:使用本地 GeoIP 数据库,无需外部 API 调用
- 速率限制:防止暴力攻击和滥用行为
- 自动清理:建议定期清理过期 token
速率限制
本包内置了完整的速率限制功能,防止暴力攻击和滥用。
配置
在 .env 文件中配置:
# 启用/禁用速率限制
SCAN_LOGIN_RATE_LIMIT_ENABLED=true
# 最大尝试次数
SCAN_LOGIN_RATE_LIMIT_MAX_ATTEMPTS=10
# 时间窗口(分钟)
SCAN_LOGIN_RATE_LIMIT_DECAY_MINUTES=1
# 限制策略:ip, user, ip_and_user, session
SCAN_LOGIN_RATE_LIMIT_STRATEGY=ip
功能特性
- ✅ 多种限制策略(IP、用户、会话)
- ✅ 针对不同操作的独立限制
- ✅ IP 白名单和黑名单
- ✅ 自动日志记录
- ✅ 优雅的错误提示
详细文档请参考 RATE_LIMITING.md。
多语言支持
本包提供完整的多语言支持,默认包含简体中文和英文。
支持的语言
- 🇨🇳 简体中文 (zh_CN)
- 🇺🇸 英文 (en)
配置语言
在 config/app.php 或 .env 中设置:
APP_LOCALE=zh_CN # 或 en
发布语言文件
php artisan vendor:publish --provider="Wuwx\LaravelScanLogin\ScanLoginServiceProvider" --tag="translations"
在视图中使用
<h1>{{ __('scan-login::scan-login.qr_code_page_title') }}</h1>
<p>{{ __('scan-login::scan-login.qr_code_page_subtitle') }}</p>
详细文档请参考 LOCALIZATION.md。
GeoIP 功能说明
本包集成了 torann/geoip 来提供基于 IP 的地理位置显示功能:
特性
- 本地数据库查询,无需外部 API 调用
- 自动缓存查询结果(24小时)
- 显示国家、省份/州、城市信息
- 可通过配置开关启用/禁用
配置
GeoIP 功能默认启用。如需禁用,在 .env 中设置:
SCAN_LOGIN_ENABLE_GEOIP=false
更新 GeoIP 数据库
建议定期更新 GeoIP 数据库以获得最准确的位置信息:
php artisan geoip:update
可以在调度任务中添加自动更新:
// app/Console/Kernel.php
protected function schedule(Schedule $schedule)
{
$schedule->command('geoip:update')->monthly();
}
故障排除
常见问题
-
QR 码不显示
- 检查
simplesoftwareio/simple-qrcode包是否正确安装 - 检查视图文件是否存在
- 检查
-
状态不更新
- 检查 Livewire 组件是否正确注册
- 检查 JavaScript 是否正常加载
-
登录失败
- 检查用户是否已认证
- 检查 Token 是否过期
- 检查状态转换是否正确
贡献
欢迎提交 Issue 和 Pull Request!
许可证
MIT License. 详见 LICENSE 文件。