Use OAuth in Laravel with GuzzleHttp & Socialite

Cái này mất của mình gần như 1 buổi để tìm ra 1 số troubles và hướng giải quyết.

Thứ nhất phải làm rõ là Socialite về bản chất nó đóng vai trò như Authenticate ! Và chỉ là Authenticate. Nó không phải là OAuth client thuần tuý ! Do đó không thể dùng nó ( native ) để request OAuth endpoint.

How to use Socialite ( Flickr )

Ok. Về cơ bản có thể ref document link sau

https://socialiteproviders.netlify.com/providers/flickr.html

Tuy nhiên sẽ cần có 1 note nhẹ. File config/session.php cần có update dưới nếu không sẽ gặp issue vui lắm.

    'same_site' => null,

Ref

https://github.com/laravel/framework/issues/8390

Xem như xong phần này thì đã có được Access token & Access token secret.

Phần còn lại là dùng 2 cái này để request tới OAuth endpoint. Ở đây mình dùng GuzzleHttp.

<?php
/**
 * Copyright (c) 2020 JOOservices Ltd
 * @author Viet Vu <jooservices@gmail.com>
 * @package XGallery
 * @license GPL
 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
 */

namespace App\OAuth;

use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Subscriber\Oauth\Oauth1;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;

class OauthClient
{
    /**
     * @param  string  $method
     * @param  string  $uri
     * @param  array  $parameters
     * @return string|object
     */
    public function request(string $method, string $uri, array $parameters = [])
    {
        $id = md5(serialize([$method, $uri, $parameters]));
        Log::stack(['oauth'])->info(
            Cache::has($id) ? 'Requesting '.$uri.' with CACHE'
                : 'Requesting '.$uri,
            [$method, $uri, $parameters]
        );

        if (Cache::has($id)) {
            return Cache::get($id);
        }

        $client   = $this->getClient();
        $response = $client->request($method, $uri, $parameters);

        if ($response->getStatusCode() !== 200) {
            return null;
        }

        /**
         * @TODO Support decode content via event
         */
        $header  = $response->getHeader('Content-Type')[0] ?? '';
        $content = (string) $response->getBody();

        if (strpos($header, 'application/json') === false) {
            return $content;
        }

        $content = json_decode($content);

        Cache::put($id, $content, 3600);
        return Cache::get($id);
    }

    protected function getClient(): Client
    {
        $stack      = HandlerStack::create();
        $middleware = new Oauth1([
            'consumer_key' => env('FLICKR_KEY'),
            'consumer_secret' => env('FLICKR_SECRET'),
            'token' => env('FLICKR_ACCESS_TOKEN'),
            'token_secret' => env('FLICKR_ACCESS_TOKEN_SECRET'),
        ]);
        $stack->push($middleware);

        return new Client(['handler' => $stack, 'auth' => 'oauth']);
    }
}

  • Sử dụng handler & stacker để sign OAuth
  • Cache & Log thì không có gì để nói

Phần còn lại là request thôi

    const REST_ENDPOINT = 'https://api.flickr.com/services/rest';

    /**
     * @param  string  $method
     * @param  array  $parameters
     * @return object|null
     */
    public function get(string $method, array $parameters = []): ?object
    {
        $content = $this->request(
            'GET',
            static::REST_ENDPOINT,
            [
                'query' => array_merge(
                    ['method' => 'flickr.'.$method],
                    $this->getDefaultFlickrParameters(),
                    $parameters
                )
            ]
        );

        if ($content->stat !== 'ok') {
            return null;
        }

        return $content;
    }

Xem như xong basic concept.

Thực tế sử dụng trong Command

    public function handle()
    {
        $flickr = app(Flickr::class);

        if (!$contacts = $flickr->get('contacts.getList')) {
            return;
        }

        for ($page = 1; $page <= $contacts->contacts->pages; $page++) {
            \App\Jobs\FlickrContacts::dispatch($page)->onConnection('database');
        }
    }

Do bản chất flickr method đều có prefix là “flickr.” do đó mình bỏ nó đi, đưa vào client class cho tiện. Khỏi mất công type.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Up ↑

%d bloggers like this: