[API 写法] QQ 登录、微信登录、Facebook、google、苹果登录

简单说明

前端 传 code 参数 ,都可以

weixin 传 code 或者 access_token

apple 传 id_token 或 access_token

EventServiceProvider

protected $listen = [

 \SocialiteProviders\Manager\SocialiteWasCalled::class => [
      'SocialiteProviders\QQ\QqExtendSocialite@handle', // QQ登录
      'SocialiteProviders\Weixin\WeixinExtendSocialite@handle', // 微信登录
  ],
];

AuthorizationsController 实例代码

<?php
namespace App\Http\Controllers\Api;
use App\Models\User;
use Faker\Generator;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Laravel\Socialite\Facades\Socialite;
class AuthorizationsController extends Controller {
    public function socialStore($type, Request $request) {
        if (!in_array($type, ['weixin', 'qq', 'facebook', 'google', 'apple'])) {
            return $this->failed('请求方式错误');
        }
        if (in_array($type, ['weixin', 'qq', 'facebook', 'google', ])) {
            $driver = Socialite::driver($type);
            try {
                if ($code = $request->code) {
                    $response = $driver->getAccessTokenResponse($code);
                    $token = array_get($response, 'access_token');
                } else {
                    $token = $request->access_token;
                    if ($type == 'weixin') {
                        $driver->setOpenId($request->openid);
                    }
                }
                $oauthUser = $driver->userFromToken($token);
            }
            catch(\Exception $e) {
                return $this->failed('参数错误,未获取用户信息');
            }
        } else {
            // apple 登录
            try {
                if ($code = $request->code) {
                    $response = http('https://appleid.apple.com/auth/token', [
                        'grant_type' => 'authorization_code',
                        'code' => $code, 
                        'redirect_uri' => config('services.apple.redirect') , 
                        'client_id' => config('services.apple.client_id') ,
                        'client_secret' => config('services.apple.client_secret') , 
                    ]);
                    $id_token = $response->id_token;
                } else {
                    $id_token = $request->access_token;
                }
                $oauthUser = json_decode(base64_decode(explode('.', $id_token) [1]));
            }
            catch(\Exception $e) {
                return $this->failed('apple 参数错误');
            }
        }
        $user = null;
        switch ($type) {
            case 'qq':
                $user = User::query()->where('open_id', $oauthUser->getId())->first();
                // 没有用户,默认创建一个用户
                if (!$user) {
                    $user = User::create([
                        'type' => User::TYPE_QQ,
                        'nickname' => $oauthUser->getNickname() ,
                        'avatar' => $oauthUser->getAvatar() ,
                        'open_id' => $oauthUser->getId() , 
                    ]);
                }
                break;

            case 'weixin':
                $user = User::query()->where('open_id', $oauthUser->getId())->first();
                // 没有用户,默认创建一个用户
                if (!$user) {
                    $user = User::create([
                        'type' => User::TYPE_WECHAT,
                        'nickname' => $oauthUser->getNickname() ,
                        'avatar' => $oauthUser->getAvatar() ,
                        'open_id' => $oauthUser->getId() ,
                        'sex' => $oauthUser['sex'] == 1 ? '男' : '女', 
                    ]);
                }
                break;

            case 'facebook':
                $user = User::query()->where('open_id', $oauthUser->getId())->first();
                // 没有用户,默认创建一个用户
                if (!$user) {
                    $user = User::create([
                    'type' => User::TYPE_FACEBOOK,
                    'nickname' => $oauthUser->getName() , 
                    'avatar' => $oauthUser->getAvatar() , 
                    'open_id' => $oauthUser->getId() ,
                    ]);
                }
                break;

            case 'google':
                $user = User::query()->where('open_id', $oauthUser->getId())->first();
                // 没有用户,默认创建一个用户
                if (!$user) {
                    $user = User::create([
                        'type' => User::TYPE_GOOGLE, 
                        'nickname' => $oauthUser->getName() , 
                        'avatar' => $oauthUser->getAvatar() ,
                        'open_id' => $oauthUser->getId() , 
                    ]);
                }
                break;

            case 'apple':
                $user = User::query()->where('open_id', $oauthUser->sub)->first();
                // 没有用户,默认创建一个用户  Faker\Generator::class
                $faker = app(Generator::class);
                if (!$user) {
                    $user = User::create([
                        'type' => User::TYPE_APPLE, 
                        'nickname' => array_key_exists('email', $oauthUser) ? $oauthUser->email : $faker->unique()->safeEmail, 
                        'open_id' => $oauthUser->sub,
                    ]);
                }
                break;
            }
            $token = Auth::guard('api')->setTTL(60 * 24 * 365)->fromUser($user);
            return $this->respondWithToken($token)->setStatusCode(201);
    }
    protected function respondWithToken($token) {
        return $this->success([
        'access_token' => 'Bearer ' . $token,
        'expires_in' => Auth::guard('api')->factory()->getTTL() ,
        ]);
    }
}

apple 登录的 http 方法

function http($url, $params = false)
{
  $ch = curl_init($url);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  if ($params) {
  curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
 }  curl_setopt($ch, CURLOPT_HTTPHEADER, [
  'Accept: application/json',
  'User-Agent: curl', # Apple requires a user agent header at the token endpoint
  ]);
  $response = curl_exec($ch);
  return json_decode($response);
}

路由

Route::post('socials/{social_type}/authorizations', 'AuthorizationsController@socialStore')->name('api.socials.authorizations.store'); // 第三方登录
本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由系统于 3年前 自动加精
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 11

socialStore 方法可以考虑再优化下

4年前 评论

很实用...

4年前 评论

不用composer加载吗

3年前 评论

干嘛不用, 驱动方式写呢?

3年前 评论

手艺良多 感谢分享!

3年前 评论

您好 为啥我用不了啊
Target [Laravel\Socialite\Contracts\Factory] is not instantiable.

3年前 评论

文中提到:

现执行查询语句,紧接着:
// 没有用户,默认创建一个用户

这段逻辑可以这样写(以QQ为例,比较简洁):

$user = User::firstOrCreate([
    'open_id' => $oauthUser->getId())->first(),
],[
    'type' => User::TYPE_QQ,
    'nickname' => $oauthUser->getNickname() ,
    'avatar' => $oauthUser->getAvatar() ,
    'open_id' => $oauthUser->getId() ,
]);

其中第一个[]参数就是查询一下数据库中是否存在与之相匹配的数据,第二个[]便是在未查询到数据的情况下,创建一个用户。
我只是提议哈,没得别的意思:blush:
然后那个switchcase语句有好多都是重复的,还可以考虑将它封装成一个可复用的函数,这样代码就简洁的灰常多了:laughing:

3年前 评论
gyp719 (楼主) 3年前

这里传code参数是指哪些参数?

2年前 评论

不错,解决了apple登录,id_token解码问题

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!