Authentication with Laravel Passport and GraphQL
Bài đăng này đã không được cập nhật trong 5 năm
Mở đầu
Chào các bạn, giờ đã là 2019 rồi, do Tết ăn nhiều bánh chưng quá nên sợ quên, nên hôm nay mình xin được chia sẻ về Authentication sử dụng Laravel Passport và GraphQL, vừa để nhớ lại kiến thức về GraphQL, vừa tìm hiểu và học thêm những điều mới. Và cũng không hiểu sao mình cứ thấy ấn tượng với anh GraphQL
này =))
Kể từ ngày công bố ra mắt vào năm 2015, tính đến nay GraphQL được Facebook công bố ra đời đã được khoảng 4 năm. Sự mạnh mẽ của GraphQL đã được rất nhiều công ty phần mềm lớn sử dụng, nổi tiếng nhất chắc chắn là Facebook . Khi nhắc đến GraphQL, điều đầu tiên mình nghĩ đến về nó đó là "Single endpoint". Trước đây mình cũng đã tìm hiểu và có những bài viết về GraphQL kết hợp với Nuxt.js, các bạn có thể tham khảo tại link này, và mình cũng đã up lên heroku để demo tại đây. Giờ chúng ta bắt đầu vào phần nội dung của bài thôi.
Nội dung
1. Cài đặt Laravel Passport (Laravel 5.7)
Clone project Laravel:
composer create-project --prefer-dist laravel/laravel passport-graphql
php artisan key:generate
composer require laravel/passport
php artisan migrate
php artisan passport:install
Sửa file User.php
:
use Laravel\Passport\HasApiTokens;
{
use HasApiTokens;
}
Sửa file AuthServiceProvider.php
:
use Laravel\Passport\Passport;
public function boot()
{
$this->registerPolicies();
Passport::routes(function ($router) {
$router->forAccessTokens();
});
}
Sửa file auth.php
:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport', //default is 'token'
'provider' => 'users',
],
],
Tạo dữ liệu cho bảng User
:
php artisan ti
factory(App\User::class, 5)->create();
Trước hết mình thử test xem Laravel Passport có hoạt động chưa:
Mình sẽ test thử bằng postman nhé
Kết quả ok rồi nhé các bạn. Điều này chứng tỏ mình đã cài đặt và sử dụng được Laravel Passport
. Giờ mình sẽ sử dụng nó với GraphQL.
2. Cài đặt GraphQL kết hợp sử dụng Laravel Passport
Ở bài viết trước đó mình cũng hướng dẫn cài đặt GraphQL cho Laravel rồi, các bạn có thể xem tại bài viết này. Tuy nhiên lần này mình sẽ sử dụng package rebing/graphql-laravel.
composer require rebing/graphql-laravel
Sau khi cài đặt, bạn run php artisan route:list
lên nếu thấy route của GraphQL
tức là bạn đã có thể sử dụng rồi.
Ở đây mình sử dụng GraphQL
sử dụng với Laravel Passport
nhưng thực chất là route khi cài đặt Passport đã có rồi, vì vậy mục đích ở đây của mình là sẽ gọi đến nó và xử lý.
Trước hết các bạn định nghĩa Schema
cho model User
như sau:
php artisan make:graphql:type UserType
Mở UserType.php
tại app\GraphQL\Type\UserType.php
:
<?php
namespace App\GraphQL\Type;
use Rebing\GraphQL\Support\Type as GraphQLType;
use GraphQL\Type\Definition\Type;
class UserType extends GraphQLType
{
public function fields()
{
return [
'id' => [
'type' => Type::nonNull(Type::int())
],
'name' => [
'type' => Type::string()
],
'email' => [
'type' => Type::string()
],
];
}
}
Tạo query users:
php artisan make:graphql:query AllUserQuery
Mục đích của mình ở đây đó là nếu người dùng nào đăng nhập thì sẽ có thể xem được tất cả thông tin của các user khác.
Có vẻ hơi sai sai nhưng đây chỉ là ví dụ thôi
Sau khi run xong command trên, các bạn sửa cho mình file AllUserQuery.php
tại app\Query\AllUserQuery.php
:
<?php
namespace App\GraphQL\Query;
use GraphQL\Type\Definition\Type;
use GraphQL;
use App\User;
use Rebing\GraphQL\Support\Query;
class AllUserQuery extends Query
{
public function type()
{
return Type::listOf(GraphQL::type('user'));
}
public function args()
{
return [
'id' => ['name' => 'id', 'type' => Type::int()],
'name' => ['name' => 'name', 'type' => Type::string()],
'email' => ['name' => 'email', 'type' => Type::string()],
];
}
public function resolve($root, $args)
{
$users = User::all();
if (isset($args['name'])) {
$users = $users->where('name', $args['name']);
}
if (isset($args['id'])) {
$users = $users->where('id', $args['id']);
}
if (isset($args['email'])) {
$users = $users->where('email', $args['email']);
}
return $users;
}
}
Sau đó bạn mở file config/graphql.php
và config cho mình như sau:
'schemas' => [
'default' => [
'query' => [
],
'mutation' => [
// 'example_mutation' => ExampleMutation::class,
],
'middleware' => [],
'method' => ['get', 'post'],
],
'secret' => [
'query' => [
'currentUser' => \App\GraphQL\Query\AllUserQuery::class,
],
'middleware' => ['auth:api']
]
],
// The types available in the application. You can then access it from the
// facade like this: GraphQL::type('user')
//
// Example:
//
// 'types' => [
// 'user' => 'App\GraphQL\Type\UserType'
// ]
//
'types' => [
'user' => \App\GraphQL\Type\UserType::class,
// 'example' => ExampleType::class,
// 'relation_example' => ExampleRelationType::class,
],
Nhìn vào đoạn code trên chắc các bạn cũng hiểu mình đang muốn làm gì rồi phải không. GraphQL
cho phép bạn có thể config các router
rất đa dạng mà vẫn đảm bảo đầy đủ những gì mà bạn vẫn thường làm với RESTful
. Thử với Postman
nhé. Nếu nó ra lỗi 401 Unauthenticated tức là mình đã config thành công.
Đúng rồi nè các bạn. Hehe.
Giờ mình sẽ dùng GraphQL
thông qua Passport để lấy access_token
. Để làm được điều này, đầu tiên mình tạo một Mutation
:
php artisan make:graphql:mutation LoginMutation
Sửa lại file app\GraphQL\Mutation\LoginMutation.php
:
<?php
namespace App\GraphQL\Mutation;
use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Mutation;
use GraphQL;
use Illuminate\Http\Request;
use Illuminate\Auth\AuthenticationException;
class LoginMutation extends Mutation
{
protected $attributes = [
'name' => 'LoginMutation',
'description' => 'A mutation'
];
public function type()
{
return Type::listOf(Type::string());
}
public function args()
{
return [
'username' => ['name' => 'username', 'type' => Type::nonNull(Type::string())],
'password' => ['name' => 'password', 'type' => Type::nonNull(Type::string())],
];
}
public function resolve($root, $args)
{
$credentials = [
'client_id' => env('PASSPORT_CLIENT_ID'),
'client_secret' => env('PASSPORT_CLIENT_SECRET'),
'grant_type' => 'password',
'username' => $args['username'],
'password' => $args['password']
];
$token = $this->makeRequest($credentials);
return $token;
}
public function makeRequest(array $credentials)
{
$request = Request::create('oauth/token', 'POST', $credentials,[], [], [
'HTTP_Accept' => 'application/json'
]);
$response = app()->handle($request);
$decodedResponse = json_decode($response->getContent(), true);
if ($response->getStatusCode() != 200) {
throw new AuthenticationException($decodedResponse['message']);
}
return $decodedResponse;
}
}
Các bạn nhớ config lại trong file graphql.php
nhé
'schemas' => [
'default' => [
'query' => [
],
'mutation' => [
'signIn' => \App\GraphQL\Mutation\LoginMutation::class
],
'middleware' => [],
'method' => ['get', 'post'],
],
'secret' => [
'query' => [
'currentUser' => \App\GraphQL\Query\AllUserQuery::class,
],
'middleware' => ['auth:api']
]
],
Mình thử test xem sao nhé
Lại đúng luôn
Lại đúng nữa rồi
Một lợi ích nữa khi sử dụng GraphQL
mà các bạn có thể thấy đó là bạn có thể lấy trường nào mà mình muốn, k nhất thiết phải phụ thuộc quá nhiều vào server
trả về những gì.
Kết luận
Với cá nhân mình, mình rất thích GraphQL
, cũng vì nó ra đời cũng không lâu, vì vậy mình luôn cố gắng để sử dụng nó kết hợp với những gì mình đã biết cũng như muốn tìm hiểu. Mình nghĩ trong tương lại không xa, GraphQL
sẽ thay thế RESTful
nhờ sự linh động của nó.
Đây là link source code của mình.
Cuối cùng, cảm ơn các bạn đã dành thời gian đọc bài viết này của mình.
All rights reserved