yfsns / laravel-wechat-login
微信登录驱动 - 支持微信扫码登录、移动端一键登录和OAuth授权
v2.1.0
2026-03-03 11:02 UTC
Requires
- php: ^8.1
- guzzlehttp/guzzle: ^7.0
- laravel/framework: ^10.0|^11.0|^12.0
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0|^10.0
- phpunit/phpunit: ^10.0|^11.0
README
微信登录驱动,实现了 YFSNS 系统的第三方登录驱动接口,支持微信扫码登录和 OAuth 授权。
功能特性
- ✅ 微信扫码登录(Web端)
- ✅ 微信移动端一键登录
- ✅ OAuth 授权登录
- ✅ 实现统一的第三方登录驱动接口
- ✅ 使用主应用的
social_accounts表 - ✅ 无需额外的数据库迁移
- ✅ 简单的安装和配置
安装
1. 安装 Package
composer require yfsns/laravel-wechat-login
2. 发布配置文件
php artisan vendor:publish --tag=config
配置
在 .env 文件中添加:
# Web端配置(扫码登录) WECHAT_APP_ID=your_app_id WECHAT_APP_SECRET=your_app_secret WECHAT_REDIRECT_URI=https://your-domain.com/api/v1/social-login/wechat/callback WECHAT_SCOPE=snsapi_login # 移动端配置(一键登录) WECHAT_MOBILE_APP_ID=your_mobile_app_id WECHAT_MOBILE_APP_SECRET=your_mobile_app_secret WECHAT_MOBILE_REDIRECT_URI=https://your-domain.com/api/v1/social-login/wechat/callback WECHAT_MOBILE_SCOPE=snsapi_userinfo
配置说明
| 配置项 | 说明 | 默认值 | 必填 |
|---|---|---|---|
| WECHAT_APP_ID | Web端App ID | - | 是 |
| WECHAT_APP_SECRET | Web端App Secret | - | 是 |
| WECHAT_REDIRECT_URI | Web端回调地址 | - | 是 |
| WECHAT_SCOPE | Web端授权范围 | snsapi_login | 否 |
| WECHAT_MOBILE_APP_ID | 移动端App ID | 使用Web端配置 | 否 |
| WECHAT_MOBILE_APP_SECRET | 移动端App Secret | 使用Web端配置 | 否 |
| WECHAT_MOBILE_REDIRECT_URI | 移动端回调地址 | 使用Web端配置 | 否 |
| WECHAT_MOBILE_SCOPE | 移动端授权范围 | snsapi_userinfo | 否 |
授权范围说明
-
Web端:
snsapi_login:扫码登录,只能获取用户openidsnsapi_userinfo:扫码登录,可以获取用户详细信息
-
移动端:
snsapi_base:静默授权,只能获取用户openidsnsapi_userinfo:弹出授权页面,可以获取用户详细信息(推荐)
使用
通过主应用的第三方登录接口使用
微信登录驱动会自动注册到主应用的第三方登录系统中,可以通过以下接口使用:
| 接口 | 说明 |
|---|---|
GET /api/v1/social-login/drivers |
获取可用登录驱动列表 |
GET /api/v1/social-login/wechat/login |
获取微信扫码登录 URL(Web端) |
GET /api/v1/social-login/wechat/mobile-login |
获取微信一键登录 URL(移动端) |
GET /api/v1/social-login/wechat/callback |
处理微信登录回调 |
前端调用示例
// 1. 获取可用驱动 fetch('/api/v1/social-login/drivers') .then(res => res.json()) .then(data => console.log(data)); // 2. Web端:获取扫码登录 URL fetch('/api/v1/social-login/wechat/login') .then(res => res.json()) .then(data => window.location.href = data.data.login_url); // 3. 移动端:获取一键登录 URL fetch('/api/v1/social-login/wechat/mobile-login') .then(res => res.json()) .then(data => window.location.href = data.data.login_url); // 4. 处理回调(后端自动处理)
微信开放平台配置
Web端扫码登录
- 登录 微信开放平台
- 创建网站应用
- 获取 App ID 和 App Secret
- 设置授权回调域名
移动端一键登录
- 登录 微信开放平台
- 创建移动应用
- 获取 App ID 和 App Secret
- 设置授权回调域名
- 在微信开发者工具中测试
驱动接口实现
微信登录驱动实现了 App\Modules\Auth\Contracts\SocialLoginDriverInterface 接口:
interface SocialLoginDriverInterface { public function getName(): string; public function getDriverType(): string; public function getLoginUrl(?string $state = null): string; public function handleCallback(string $code): array; public function getUserInfo(string $accessToken, string $openid): array; public function getConfigFields(): array; public function validateConfig(array $config): array; public function setConfig(array $config): void; public function getConfig(): array; public function testConnection(): array; }
数据存储
微信登录驱动使用主应用的 social_accounts 表存储用户信息:
CREATE TABLE social_accounts ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, user_id BIGINT UNSIGNED NOT NULL COMMENT '关联用户ID', driver VARCHAR(50) NOT NULL COMMENT '第三方登录驱动', openid VARCHAR(255) NOT NULL COMMENT '第三方用户唯一标识', unionid VARCHAR(255) NULL COMMENT '第三方开放平台唯一标识', nickname VARCHAR(255) NULL COMMENT '第三方昵称', avatar VARCHAR(500) NULL COMMENT '第三方头像', data JSON NULL COMMENT '原始数据', created_at TIMESTAMP NULL, updated_at TIMESTAMP NULL, INDEX idx_user_id (user_id), INDEX idx_driver_openid (driver, openid), UNIQUE KEY uk_driver_openid (driver, openid), FOREIGN KEY fk_user_id (user_id) REFERENCES users(id) ON DELETE CASCADE ) COMMENT='第三方登录账号表';
扩展包开发指南
创建新的第三方登录驱动
参考 WeChatLoginDriver 实现 SocialLoginDriverInterface:
<?php namespace Your\Namespace\Drivers; use App\Modules\Auth\Contracts\SocialLoginDriverInterface; class YourLoginDriver implements SocialLoginDriverInterface { protected array $config; public function __construct(array $config = []) { $this->config = $config; } public function getName(): string { return '你的驱动名称'; } public function getDriverType(): string { return 'oauth2'; } public function getLoginUrl(?string $state = null): string { $params = [ 'client_id' => $this->config['client_id'] ?? '', 'redirect_uri' => $this->config['redirect_uri'] ?? '', 'response_type' => 'code', 'scope' => $this->config['scope'] ?? '', 'state' => $state ?? md5(uniqid('', true)), ]; return 'https://api.example.com/oauth/authorize?' . http_build_query($params); } public function handleCallback(string $code): array { $tokenData = $this->getAccessToken($code); return $this->getUserInfo($tokenData['access_token'], $tokenData['openid']); } public function getUserInfo(string $accessToken, string $openid): array { return [ 'openid' => $openid, 'unionid' => null, 'nickname' => '用户昵称', 'avatar' => '用户头像', 'data' => [], ]; } public function getConfigFields(): array { return [ [ 'key' => 'client_id', 'label' => 'Client ID', 'type' => 'string', 'required' => true, ], [ 'key' => 'client_secret', 'label' => 'Client Secret', 'type' => 'string', 'required' => true, ], ]; } public function validateConfig(array $config): array { $errors = []; if (empty($config['client_id'])) { $errors['client_id'] = 'Client ID 不能为空'; } return $errors; } public function setConfig(array $config): void { $this->config = array_merge($this->config, $config); } public function getConfig(): array { return $this->config; } public function testConnection(): array { return [ 'success' => true, 'message' => '连接测试成功', ]; } }
在 ServiceProvider 中注册
<?php namespace Your\Namespace; use Illuminate\Support\ServiceProvider; use Your\Namespace\Drivers\YourLoginDriver; class YourLoginServiceProvider extends ServiceProvider { public function register() { $this->mergeConfigFrom( __DIR__ . '/config/your-login.php', 'your-login' ); } public function boot() { if ($this->app->runningInConsole()) { $this->publishes([ __DIR__ . '/config/your-login.php' => config_path('your-login.php'), ], 'config'); } $this->registerDriver(); } protected function registerDriver(): void { if (!$this->isInterfaceAvailable()) { return; } $this->app->singleton(YourLoginDriver::class, function ($app) { return new YourLoginDriver(config('your-login')); }); if ($this->app->bound(\App\Modules\Auth\Drivers\Registry\SocialLoginDriverRegistryInterface::class)) { $registry = $this->app->make(\App\Modules\Auth\Drivers\Registry\SocialLoginDriverRegistryInterface::class); $registry->registerDriver('your-driver', YourLoginDriver::class); } } protected function isInterfaceAvailable(): bool { return interface_exists('App\\Modules\\Auth\\Drivers\\Registry\\SocialLoginDriverRegistryInterface'); } }
更新日志
v2.1.0 (2026-03-03)
- ✨ 新增移动端一键登录支持
- ✨ 新增
getMobileLoginUrl()方法 - ✨ 新增
getWebLoginUrl()方法 - ✨ 新增移动端配置选项(mobile_app_id, mobile_app_secret, mobile_redirect_uri, mobile_scope)
- ✨ 支持独立的 Web 端和移动端配置
- 📝 更新文档,说明移动端登录的使用方法
v2.0.0 (2026-02-24)
- 🔄 重构为驱动模式
- 🔄 删除独立的数据库迁移
- 🔄 删除独立的控制器和服务
- 🔄 使用主应用的
social_accounts表 - ✨ 实现统一的第三方登录驱动接口
- ✨ 简化安装和配置流程
v1.0.0 (2025-01-01)
- 初始版本发布
- 支持微信扫码登录
- 支持自动创建用户
- 支持用户信息同步
贡献
欢迎提交 Issue 和 Pull Request!
许可证
MIT License
作者
YFSNS Team
支持
如有问题,请提交 Issue 或联系作者。