Open sinkcup opened 5 years ago
完全没明白原有的微信登录有什么问题(除了名字叫 weixin),导致你需要在 SocialiteProviders 另开一份。
你使用了一个对 scopes 配置的 hack,只是为了解决自己项目里需要拿 unionid 来做 provider_user_id 的需要。然而 unionid 是微信特有的一个东西,如果需要对它特殊处理,完全应该在 SocialiteProviders 之外的业务代码里去处理(比如在 sinkcup/laravel-make-auth-socialite 里处理)
你这样对于不是很了解 oauth2 协议的使用者来说,会更容易混淆 scopes 是干嘛的。
在我维护的不少项目里,都需要将微信以及QQ的 openid 和 unionid 都存下来(它们各有用途),我会在业务里使用这样的代码来处理这块:
if (isset($providerUser->user) && isset($providerUser->user['unionid'])) {
$social->unionid = $providerUser->user['unionid'];
} elseif (isset($providerUser->unionid) && $providerUser->unionid) {
$social->unionid = $providerUser->unionid;
}
另外,原有的 weixin 模块,提供 setOpenId 的支持,对于需要单独调用 userFromToken 函数的场景,也会比你支持的更好。
如果你试着做过 facebook 一个开发者账号下,多应用的 openid 打通。你会发现,因为 unionid 这种特殊情况去改动模块是没有意义的。如果使用者是一个开箱即用的简单模式,他用不到类似 unionid 这样特有的东西,如果他需要用到,就应该了解,这个没法很好通用封装。
@apollopy unionid 特殊但又可以通过 scope 标准化,而无需添加任何业务代码。而 openid 在 raw 里保存,不影响业务使用。具体解释在这里:https://sinkcup.github.io/code-explaination-of-laravel-socialite-wechat-login
这篇文章我昨晚就仔细读过了。我还是保留我的想法。原因:
我注意到你提到的 不方便切换 snsapi_base(服务号免授权登录) 和 snsapi_userinfo
,我实际还没接服务号,但这看上去像是 weixin 包的一个 bug,我们可以提 pr fix 它。
从微信的文档来说,openid 更符合 Laravel\Socialite\AbstractUser 里定义的 id。不管是请求用户资料的 https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
接口,还是服务号发送消息的接口 https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Template_Message_Interface.html#5
。拿到用户授权之后,几乎所有和账号有关的操作,都需要声明 openid。
而 unionid 仅仅是一种用来打通同一家公司跨应用用户身份的唯一标示,只不过微信和QQ选择的跨应用打通方案,恰巧可以在你的场景里,直接拿来做唯一标示而已。这个即使在 sinkcup/laravel-make-auth-socialite 里封装,也能让其他使用者无需添加任何业务代码。
就像你说的,openid 在 raw 里保存。反过来说,之前的包,unionid 在 raw 里保存,他也可以说不影响用户使用。这其实没有对错,只是个见仁见智的问题。
相比旧包没做任何 hack,让需要用 unionid 的人自己在业务代码里处理。你选择用 scopes 去 hack,这个 hack 侵入 Laravel\Socialite 通用设计过深。
旧包 weixin 这个名字确实很恶心。但考虑到这个包的使用非常广泛,名字、以及用哪个做 Laravel\Socialite\AbstractUser 里定义的 id,我觉得都不是另开一个包的充分理由。假设微信后面有做改动,我们就需要维护4个包的相似代码了。
我昨天刚看到你提交的包,第一个想法是,啊终于有个名字对的包了,下次开新项目我用这个,这样以后 IDE 就不会有一个拼写警告了,然而仔细看了代码,这个新包并不友好。
利用 scopes 来 hack,我实在不能觉得这是优雅的。scopes 是用来定义向终端用户以及 Authorization Server 申请授权范围用的,理论上 scopes 里有什么,只有微信能定义,只要它定义上不出现命名冲突就行了。极端点说,如果之后微信的 scopes 用了跟你 hack 相同的命名,你怎么办?
请注意你的包 userFromToken 这个 public 函数不能独立运行了,必须在同一进程里,先执行 getAccessTokenResponse ,再执行 userFromToken 才行。
@apollopy 微信有两种场景:默认openid,无需打通;或者 默认 unionid,自动打通。我写的包都支持。第2种情况时,微信跨应用需要唯一标示,所以 unionid 作为 AbstractUser 的 id 很合适。unionid 放在 scopes 里,本来微信API就应该这么定义,而实际上腾讯技术太差了,微信API非常不规范,目前这么hack我觉得已经是最优雅的做法了,而 sinkcup/laravel-make-auth-socialite 是一个脚手架,并不是必须安装的,大部分人只安装了 Socialite 和 providers,然后无需处理 unionid 就能用了,这很好。而你担心的微信scopes如果用了unionid,怎么办?那到时候当然要更新这个包了。
老包的名字错了,这只是其中一个理由,关键是它的代码已经烂掉了,由于它使用很广泛,所以只能重做新的,而无法改名。而你担心的“一旦微信变了,我们要维护2个包”,这完全不用担心,你看老包的代码里面还有注释掉的代码、毫无书写规范,应该明白很多开源项目往往是没人维护的,没人提pr去fix。
由于微信API不符合oauth 2的标准,在返回openid的时候返回了user info,需要hack,所以我在 socialiteproviders/manager 3.3.6 里预先设置了 credentialsResponseBody,userFromToken 应该可以调用,而不依赖 getAccessTokenResponse。不知你说的是什么问题,可以提个issue详细说一下。
@apollopy 名字错了,这一个理由就足够废弃它了。就像数据库字段,错了,那就会后患无穷,尽早废弃才好。开源项目 就是这样,大家觉得不爽,都可以另起炉灶,没人想去维护一个连名字都不规范的项目,代码更不规范。
由于微信并不能光用 token 拿到用户信息,还需要传递 openid。原包里
https://github.com/SocialiteProviders/Providers/blob/master/src/Weixin/Provider.php#L133
https://github.com/SocialiteProviders/Providers/blob/master/src/Weixin/Provider.php#L30-L33
这两段,保证了我既能用过 user() 函数直接实现。也能在已知 openid 和 token 的情况下,自己 new 这个类,通过 userFromToken 拿到 Laravel\Socialite\AbstractUser
而 credentialsResponseBody 目前是没办法在外部设置的。导致抽象类里的 https://github.com/laravel/socialite/blob/4.0/src/Two/AbstractProvider.php#L230 作为一个 public 函数,完全没办法使用
@sinkcup, can you please explain what is the difference between WeChatWeb and WeChatServiceAccount providers?
Sorry if it's a dumb question, I'm not a Chinese person and I don't use WeChat much, but I have to integrate it with my website.
@neochief WeChatWeb: used on Web, show a QR code, notice people: use phone wechat app to scan. WeChatServiceAccount: used in phone, user access login url in wechat app webview, wechat app will show grant scopes button not QR code.
@apollopy userFromToken 可以用了,你注意到了吗?
@sinkcup, thank you for the answer! I'm a bit puzzled, does it means that I should present 2 login buttons in UI for Web and QR code? I would be very grateful if you can show me any Chinese website that implements the login routine with both WeChat providers.
@neochief jianshu.com is a good example, it has good technology.
you will see the same account as the web.
https://sinkcup.github.io/laravel-socialite-wechat-login
最近做的 Laravel 网站项目需要微信登录功能,看了下官方文档, Laravel 通过官方扩展包——Socialite 来做 OAuth 登录,官方支持 Facebook、 Twitter、 LinkedIn、 Google、GitHub 和 Bitbucket,其他登录渠道依靠开源项目——Socialite Providers,但里面的微信登录有问题,所以我重做了一个开源项目 Laravel Socialite Providers。