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