使用 Laravel Socialite 集成微信登陸

Laravel Socialite

Laravel Socialite provides an expressive, fluent interface to OAuth authentication with Facebook, Twitter, Google, LinkedIn, GitHub and Bitbucket. It handles almost all of the boilerplate social authentication code you are dreading writing.php

Laravel Socialite 爲第三方應用的 OAuth 認證提供了很是豐富友好的接口,咱們使用它能夠很是方便快捷的對相似微信、微博等第三方登陸進行集成。laravel

Open Authorization

OAuth(開放受權)是一個開放標準,容許用戶讓第三方應用訪問該用戶在某一網站上存儲的私密的資源(如照片,視頻,聯繫人列表),而無需將用戶名和密碼提供給第三方應用。git

OAuth 容許用戶提供一個令牌,而不是用戶名和密碼來訪問他們存放在特定服務提供者的數據。每個令牌受權一個特定的網站(例如,視頻編輯網站)在特定的時段(例如,接下來的 2 小時內)內訪問特定的資源(例如僅僅是某一相冊中的視頻)。這樣,OAuth 讓用戶能夠受權第三方網站訪問他們存儲在另外服務提供者的某些特定信息,而非全部內容。github

咱們的應用與使用 OAuth 標準的第三方應用的交互流程通常是這樣的:web

  • 展現跳轉到第三方應用登陸的連接express

  • 用戶點擊連接跳轉到第三方應用登陸並進行受權json

  • 在用戶受權後第三方應用會跳轉到咱們所指定的應用回調資源地址並伴隨用於交互 AccessToken 的 Codeapi

  • 咱們的應用拿到 Code 後自主請求第三方應用並使用 Code 獲取該用戶的 AccessToken微信

  • 獲取 AccessToken 以後的應用便可自主的從第三方應用中獲取用戶的資源信息app

Laravel Socialite UML

Socialite

安裝 Laravel Socialite

使用 Composer 進行安裝:

composer require laravel/socialite

配置

你須要在 config/app.phpproviders 鍵中追加:

'providers' => [
    // Other service providers...

    Laravel\Socialite\SocialiteServiceProvider::class,
],

aliasses 鍵中添加 Socialite:

'Socialite' => Laravel\Socialite\Facades\Socialite::class,

config/services.php 配置文件中添加驅動器配置項:

'github' => [
    'client_id' => 'your-github-app-id',
    'client_secret' => 'your-github-app-secret',
    'redirect' => 'http://your-callback-url',
],

至此整個流程安裝完畢。

集成微信登陸

集成微信咱們須要提供一個 WechatServiceProvider 和 一個 WechatProvider,用這兩個文件來爲微信登陸提供驅動,Laravel Socialite 的 SocialiteManager 繼承自 Illuminate\Support\Manager 類,而其對自定義驅動提供了友好的接口支持,因此咱們能夠手動的添加一個 Wechat 驅動器:

<?php

namespace Crowdfunding\Providers\Socialite;

use Laravel\Socialite\Two\AbstractProvider;
use Laravel\Socialite\Contracts\Provider as ProviderInterface;
use Laravel\Socialite\Two\User;
use GuzzleHttp\ClientInterface;

class WechatProvider extends AbstractProvider implements ProviderInterface
{
    /**
    * openid for get user.
    * @var string
    */
    protected $openId;

    /**
     * set Open Id.
     *
     * @param  string  $openId
     */
    public function setOpenId($openId) {
        $this->openId = $openId;

        return $this;
    }

    /**
     * {@inheritdoc}.
     */
    protected $scopes = ['snsapi_login'];

    /**
     * {@inheritdoc}.
     */
    public function getAuthUrl($state)
    {
        return $this->buildAuthUrlFromBase('https://open.weixin.qq.com/connect/qrconnect', $state);
    }

    /**
     * {@inheritdoc}.
     */
    protected function buildAuthUrlFromBase($url, $state)
    {
        $query = http_build_query($this->getCodeFields($state), '', '&', $this->encodingType);

        return $url.'?'.$query.'#wechat_redirect';
    }

    /**
     * {@inheritdoc}.
     */
    protected function getCodeFields($state = null)
    {
        return [
            'appid'         => $this->clientId, 'redirect_uri' => $this->redirectUrl,
            'response_type' => 'code', 'scope'                 => $this->formatScopes($this->scopes, $this->scopeSeparator),
            'state'         => $state,
        ];
    }

    /**
     * {@inheritdoc}.
     */
    public function getTokenUrl()
    {
        return 'https://api.weixin.qq.com/sns/oauth2/access_token';
    }

    /**
     * {@inheritdoc}.
     */
    public function getUserByToken($token)
    {
        $response = $this->getHttpClient()->get('https://api.weixin.qq.com/sns/userinfo', [
            'query' => [
                'access_token' => $token,
                'openid'       => $this->openId,
                'lang'         => 'zh_CN',
            ],
        ]);

        return json_decode($response->getBody(), true);

    }

    /**
     * {@inheritdoc}.
     */
    public function mapUserToObject(array $user)
    {
        return (new User())->setRaw($user)->map([
          'openid' => $user['openid'], 'nickname' => $user['nickname'],
          'avatar' => $user['headimgurl'], 'name' => $user['nickname'],
          'email'  => null, 'unionid'             => $user['unionid']
        ]);
    }

    /**
    * {@inheritdoc}.
    */
    protected function getTokenFields($code)
    {
        return [
            'appid' => $this->clientId, 'secret' => $this->clientSecret,
            'code' => $code, 'grant_type' => 'authorization_code',
        ];
    }

    /**
    * {@inheritdoc}.
    */
    public function getAccessTokenResponse($code)
    {
        $postKey = (version_compare(ClientInterface::VERSION, '6') === 1) ? 'form_params' : 'body';

        $response = $this->getHttpClient()->post($this->getTokenUrl(), [
            'headers' => ['Accept' => 'application/json'],
            $postKey => $this->getTokenFields($code),
        ]);

        $responseBody = json_decode($response->getBody(), true);
        $this->setOpenId($responseBody['openid']);

        return $responseBody;
    }
}

編寫完驅動以後咱們須要註冊該驅動器到 SocialiteManager 中,所以咱們編寫一個 WechatServiceProvider:

<?php

namespace Crowdfunding\Providers\Socialite;

use Illuminate\Support\ServiceProvider;

class WechatServiceProvider extends ServiceProvider
{
    public function boot()
    {
       $this->app->make('Laravel\Socialite\Contracts\Factory')->extend('wechat', function ($app) {
            $config = $app['config']['services.wechat'];
            return new WechatProvider(
                $app['request'], $config['client_id'],
                $config['client_secret'], $config['redirect']
            );
       });
    }
    public function register()
    {

    }
}

接着咱們就能夠添加配置項及將服務提供者註冊到 Laravel 中:

// app.php
'providers' => [
    // Other service providers...
    Crowdfunding\Providers\Socialite\WechatServiceProvider::class,
],

// services.php
'wechat' => [
    'client_id' => 'appid',
    'client_secret' => 'appSecret',
    'redirect' => 'http://xxxxxx.proxy.qqbrowser.cc/oauth/callback/driver/wechat',
]

緊接着添加路由及控制器:

// route.php
Route::group(['middleware' => 'web'], function () {
    Route::get('oauth/callback/driver/{driver}', 'OAuthAuthorizationController@handleProviderCallback');
    Route::get('oauth/redirect/driver/{driver}', 'OauthAuthorizationController@redirectToProvider');
});

控制器:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Http\Requests;
use Socialite;

class OAuthAuthorizationController extends Controller
{
    //
    public function redirectToProvider($driver) {
        return Socialite::driver($driver)->redirect();
    }

    public function handleProviderCallback($driver) {
        $user =  Socialite::driver($driver)->user();
        // dd($user)
    }

}

至此集成完畢。

PS: 歡迎關注簡書 Laravel 專題,也歡迎 Laravel 相關文章的投稿 :),做者知識技能水平有限,若是你有更好的設計方案歡迎討論 :)

相關文章
相關標籤/搜索