Google API + Laravel: Setup một project Goravel hoàn hảo!

Bài viết này sẽ hướng dẫn các bạn tự setup một project Laravel sử dụng Google API một cách tốt nhất có thể (ít ra là tốt với mình :> ) Nếu có gì sai sót hoặc chưa tối ưu, các bạn vui lòng góp ý để mình chỉnh sửa lại tốt hơn 😄

1. Chuẩn bị

Dĩ nhiên là cần một bộ project Laravel mới kính coong không tạp nham rồi. Ngoài ra bạn nên nâng cấp môi trường phát triển lên bản PHP 7.2 để support Laravel tốt nhất (Bản Laravel 5.6^ đã yêu cầu phải sử dụng PHP 7 rồi mà ).

Một tài khoản Google (có kích hoạt G-suite càng tốt)

  • Laravel 5.6.*
  • Google account
  • PHP 7.0^
  • npm, composer, git
  • Ubuntu (nếu có)

Sau khi chuẩn bị xong những thứ kia thì chúng ta cùng bắt tay vào làm từng bước thôi:

Cài đặt credentials

Đây là bước cấp quyền cho tài khoản Google để được phép truy cập vào các API.

Bạn truy cập đường dẫn sau: https://console.developers.google.com/

Đăng nhập tài khoản Google của bạn.

Sau khi đăng nhập xong bạn sẽ được chuyển hướng vào trang dashboard của mình.

Tạo một project:

Chọn ô Select a project như hình dưới, sau đó chọn một project hoặc tạo mới nếu bạn chưa có

Sau khi tạo xong, bạn chọn project vừa tạo, chọn Credentials và create credentials như hình dưới:

Chọn Other, nhập tên và bấm Create

Sau khi tạo xong bạn tải key này xuống sẽ được một file có tên: client_secret.etc..json Các bạn lưu file này ở một chỗ nào đó dễ tìm, chúng ta sẽ sử dụng nó ngay bây giờ đây.

Cơ bản như vậy là hoàn thành các bước cấu hình tài khoản Google. Tiếp theo sẽ là cấu hình Google Client cho project Laravel.

Cấu hình Google Client cho Laravel

Google đã tạo ra một bộ thư viện để developer tương tác với APIs của họ một cách đơn giản hơn.

Để sử dụng bộ thư viện này bạn chạy lệnh:

composer require google/apiclient:"^2.0"

OK vậy là tương đối ngon rồi. Các bạn tìm lại file client_secret.etc..json đã tải xuống ở bước trước sau đó tạo một thư mục có tên google trong storage. Đây là thư mục sẽ chứa các file xác thực tài khoản Google của bạn. Sau khi tạo xong, bạn copy file client_secret.etc..json vào thư mục này, đổi tên thành credentials.json cho dễ tìm :3

Bạn tạo tiếp một file google-api.php trong config, file này sẽ lấy ra thông số của credentials và cả một thứ gọi là token ở bước sau nữa.

google-api.php

return [
    'client_path' => storage_path('google/credentials.json'),
    'token_path' => storage_path('google/token.json'),
];

Lấy token

Để có thể sử dụng các API của Google thì chúng ta cần thực hiện một bước quan trọng nữa đó là xác thực người dùng. Mỗi một request đến các endpoints của Google đều cần đến một thứ gọi là token, nó dùng để xác thực tài khoản có được phép sử dụng các API hay không và được sử dụng những API nào.

Các bước lấy token này nếu lấy thủ công sẽ khá là lằng nhằng phức tạp nên mình đã tạo ra một bộ command nhỏ để chúng ta có thể thực hiện dễ dàng hơn.

Đầu tiên các bạn tạo ra một Laravel Command bằng câu lệnh:

php artisan make:command <tên command>
ex:
php artisan make:command GoogleGetToken

Một file sẽ được tạo trong app > Console > Commands tên là GoogleGetToken. Các bạn mở file này lên và bắt đầu code nào.

Nếu ai chưa từng làm việc này lần nào thì nên chú ý đến một số thứ sau:

protected $signature = 'command:name'; //tên command
//giống như php artisan make:controller chẳng hạn

// của chúng ta sẽ là
protected $signature = 'google:get-token';

public function handle()
{
    // nơi viết code xử lý cho command
}

Bắt đầu code thôi. Trong hàm handle() các bạn viết như sau:

$client = $this->getClient(); // lấy dữ liệu client (sẽ viết ở dưới)

$credentialsPath = config('google-api.token_path'); // lấy đường dẫn đến token cũ

// kiểm tra xem file token đó có đang tồn tại hay không
if (file_exists($credentialsPath)
    // nếu có hỏi lại có muốn làm mới token này hay không
    && !$this->confirm('Token is ready to use! Do you want to retrieve the token?')
) {
    //nếu không tồn tại file token thì trả ra thông báo
    return $this->info('Old token still held!');
}

// hàm get token
$this->runGetToken($client, $credentialsPath);

Các function con:

Get client

private function getClient()
{
    $client = new \Google_Client(); // khởi tạo Google Client
    $client->setApplicationName('Demo Laravel'); // đặt tên cho ứng dụng (không quan trọng lắm)
    
    // cài đặt xin quyền truy cập của token, ở đây tôi đang xin truy cập đến dữ liệu Calendar và Drive
    $client->setScopes([
        \Google_Service_Calendar::CALENDAR,
        \Google_Service_Drive::DRIVE,
    ]);
    $client->setAuthConfig(config('google-api.client_path')); // đường dẫn đến file credentials.json
    $client->setAccessType('offline'); // không rõ lắm nên cứ để vậy đi :">

    return $client;
}

Get token

Phần này khá là phức tạp nên mình sẽ chia nhỏ function này ra

private function runGetToken(\Google_Client $client, $credentialsPath)
{
    // Yêu cầu xác thực từ phía User
    $this->info("Open the following link in your browser:");
    $this->comment($client->createAuthUrl());
    $authCode = trim($this->ask('Enter verification code'));
}

Ok chạy thử phát đã, các bạn mở cửa sổ command trong thư mục Laravel của mình và chạy lệnh:

php artisan google:get-token

Khi chạy các dòng này trên cửa sổ command, bạn sẽ được yêu cầu truy cập đường dẫn đã được Google tạo ra (chính là dòng màu vàng đó)

Sau khi mở link này, các bạn sẽ được yêu cầu đăng nhập tài khoản Google, sau đó đồng ý với các quyền được yêu cầu tương ứng với các Scope mà các bạn đã khai báo trong hàm setScopes ở trên, bấm Allow để đồng ý, các bạn sẽ được cấp một đoạn mã như thế này:

Cứ tạm để nó đó, chúng ta viết tiếp code cho function runGetToken

private function runGetToken(\Google_Client $client, $credentialsPath)
{
    // Yêu cầu xác thực từ phía User
    $this->info("Open the following link in your browser:");
    $this->comment($client->createAuthUrl());
    $authCode = trim($this->ask('Enter verification code'));
    
    $accessToken = $client->fetchAccessTokenWithAuthCode($authCode);

    // Kiểm tra lỗi
    if (array_key_exists('error', $accessToken)) {
        throw new \Exception(join(', ', $accessToken));
    }

    // Lưu token vào file
    if (!file_exists(dirname($credentialsPath))) {
        mkdir(dirname($credentialsPath), 0777, true); nhớ để quyền truy cập file là 777 nhé
    }
    file_put_contents($credentialsPath, json_encode($accessToken));
    $this->info("Credentials saved to {$credentialsPath}!", $credentialsPath);
}

Sau khi hoàn thành, bạn có thể chạy lại php artisan google:get-token để lấy token mới và dán vào phần Enter vertification code, đoạn token này sẽ được lưu lại và sử dụng sau này trong quá trình phát triển các chức năng tương tác với API Google.

Tạo lớp lấy dữ liệu Client

Đến bước này là cũng sắp xong rồi đó, chúng ta sẽ tạo ra một Class để lấy dữ liệu Client từ token mà chúng ta đã "xin" được của Google.

Các bạn tạo một thư mục tên là Components trong thư mục app, tạo một file tên Google_Client trong thư mục này.

Và đây là code của nó:

use Google_Client as BaseGoogleClient;

/**
 * Class GoogleClient
 * @package App\Components
 */
class GoogleClient
{
    /**
     * @var BaseGoogleClient
     */
    protected $client;

    /**
     * GoogleClient constructor.
     * @param BaseGoogleClient $client
     */
    public function __construct(BaseGoogleClient $client)
    {
        $this->client = $client;
    }

    /**
     * @return BaseGoogleClient
     * @throws \Exception
     */
    public function getClient()
    {
        //kiểm tra credentials và token có tồn tại hay không
        if (!file_exists(config('google-api.client_path'))) {
            throw new \Exception(
                'You have not create client for application.'
                .' Please create on "console.google.com" and save to your storage "storage/google/credentials.json"!'
            );
        }
        $this->client->setAuthConfig(config('google-api.client_path'));
        $this->client->setAccessType('offline');

        $credentialsPath = config('google-api.token_path');
        if (!file_exists($credentialsPath)) {
            throw new \Exception('Do not receive access token. Please run command "php artisan google:get-token" to get token!');
        }

        $accessToken = json_decode(file_get_contents($credentialsPath), true);
        $this->client->setAccessToken($accessToken);
        
        // nếu token hết hạn sẽ tiến hành refresh lại token để sử dụng
        if($this->client->isAccessTokenExpired()) {
            $this->client->fetchAccessTokenWithRefreshToken($this->client->getRefreshToken());
            file_put_contents($credentialsPath, json_encode($this->client->getAccessToken()));
        }

        return $this->client;
    }
}

OK vậy là bạn đã có một Goravel "ngon" cho các công việc liên quan đến API Google sau này rồi 😄 Để sử dụng cũng rất đơn giản, chỉ cần inject vào hàm __construct trong class giống như sau:

use App\Components\GoogleClient;
//

protected $client;
//

public function __construct(GoogleClient $client) {
    $this->client = $client->getClient();
}

Sau đó bạn có thể dùng $this->client này để làm gì tùy thích :v

Nếu muốn cài đặt thêm quyền chỉ cần quay lại hàm getClient() trong file command GoogleGetToken thêm vào là xong.

Có thể mình sẽ làm thêm một series về cách sử dụng Goravel này cộng với một số API phổ biến của Google như là Calendar, Drive, Mail,... Rất mong mọi người ủng hộ.

Cám ơn đã theo dõi bài viết!