[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 协议》,转载必须注明作者和本文链接
本帖由系统于 4年前 自动加精
socialStore
方法可以考虑再优化下很实用...
不用composer加载吗
@voyager-a 接着上一篇博文
干嘛不用, 驱动方式写呢?
手艺良多 感谢分享!
您好 为啥我用不了啊
Target [Laravel\Socialite\Contracts\Factory] is not instantiable.
文中提到:
这段逻辑可以这样写(以QQ为例,比较简洁):
其中第一个

[]
参数就是查询一下数据库中是否存在与之相匹配的数据,第二个[]
便是在未查询到数据的情况下,创建一个用户。我只是提议哈,没得别的意思
然后那个
switch
的case
语句有好多都是重复的,还可以考虑将它封装成一个可复用的函数,这样代码就简洁的灰常多了这里传code参数是指哪些参数?
不错,解决了apple登录,id_token解码问题