Site icon Bệ Phóng Việt

Xây dựng Web Service cho chức năng đăng ký, đăng nhập… trên Laravel

Advertisements

Trong bài viết này, bạn sẽ học cách sử dụng Framework Laravel của PHP để viết 1 RESTful Web Service API. Ứng dụng này sẽ có các RESTful API cho việc

  1. Đăng ký tài khoản mới (register)
  2. Đăng nhập (authentication)
  3. Thay đổi mật khẩu (change password)

Cấu trúc cơ sở dữ liệu (MySQL)

Chúng ta sẽ tạo bảng users trong cơ sở dữ liệu với cấu trúc sau:

CREATE TABLE users ( 
  id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, 
  name VARCHAR(255) NOT NULL, 
  email VARCHAR(255) NOT NULL UNIQUE, 
  password VARCHAR(255) NOT NULL, 
  email_verified_at DATETIME, 
  remember_token VARCHAR(100), 
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, 
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

Trong câu lệnh trên, chúng ta đã tạo bảng users với các trường sau:

Chú ý bạn không cần chạy lệnh SQL này, ở bước sau chúng ta sẽ dùng migrate của Laravel để thực hiện việc khởi tạo các bảng cơ bản của hệ thống.

Sử dụng Laravel Passport

Chúng ta muốn có 1 vài api đòi hỏi user phải đã đăng nhập thành công từ API /user/login.

user/login do đó sẽ trả về 1 chuỗi token để các api trong nhóm cần có đăng nhập có thể sử dụng. Để thực hiện được việc này, chúng ta sẽ sử dung Laravel Passport. Bạn hãy chạy các lệnh sau:

composer require laravel/passport
php artisan migrate

php artisan passport:install

Update file App\Providers\AuthServiceProvider với đoạn code sau:

protected $policies = [
  'App\Models\Model' => 'App\Policies\ModelPolicy', 
];

Cập nhật config/auth.php và thêm config cho api:

'guards' => [
  'web' => [
    'driver' => 'session',
    'provider' => 'users',
  ],

  'api' => [
    'driver' => 'passport', 
    'provider' => 'users',
  ],
],

Xây dựng Model cho bảng user

Để tạo model User cho một RESTful web service API bằng Laravel, bạn có thể sử dụng các bước sau:

  1. Tạo model User bằng cách sử dụng lệnh php artisan make:model User -m.
  2. Trong model, khai báo các validation rules cho các trường dữ liệu cần thiết cho các chức năng đăng ký, xác nhận, đăng nhập và thay đổi mật khẩu.
  3. Sử dụng trait Illuminate\Foundation\Auth\VerifiesEmails để hỗ trợ chức năng xác nhận email.

Ví dụ:

<?php 

namespace App\Models;

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;
use Illuminate\Foundation\Auth\VerifiesEmails; 
use Illuminate\Database\Eloquent\Model; 


class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    public static $registerRules = [
        'name' => 'required|string|max:255',
        'email' => 'required|string|email|max:255|unique:users',
        'password' => 'required|string|min:6|confirmed',
    ];

    public static $updatePasswordRules = [
        'current_password' => 'required',
        'password' => 'required|string|min:6|confirmed',
    ];
}

Xây dựng Controller cho Web Service API

Bây giờ, chúng ta sẽ tạo UserController để có các action cho việc tạo tài khoản mới, xác nhận qua email tài khoản vừa tạo, đăng nhập và thay đổi mật khẩu.

Để tạo UserController và các action cho việc tạo tài khoản mới, xác nhận qua email tài khoản vừa tạo, đăng nhập và thay đổi mật khẩu, bạn có thể thực hiện các bước sau:

  1. Tạo UserController bằng cách sử dụng lệnh php artisan make:controller UserController.
  2. Trong UserController, tạo các action sau:
<?php 
namespace App\Http\Controllers; 
use App\Models\User; 
use Illuminate\Http\Request; 
use Illuminate\Support\Facades\Auth; 
use Illuminate\Support\Facades\Validator; 

class UserController extends Controller { 
    public function register(Request $request) { 
        $validator = Validator::make($request->all(), User::$registerRules);
        if ($validator->fails()) {
            return response()->json(['errors' => $validator->errors()], 422);
        }

        $user = new User();
        $user->name = $request->name;
        $user->email = $request->email;
        $user->password = bcrypt($request->password);
        $user->save();

        return response()->json(['message' => 'Successfully registered'], 201);
    }

    public function verify(Request $request)
    {
        $user = User::find($request->id);
        $user->email_verified_at = now();
        $user->save();

        return response()->json(['message' => 'Successfully verified'], 200);
    }

    public function login(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'email' => 'required|email',
            'password' => 'required',
        ]);
        if ($validator->fails()) {
            return response()->json(['errors' => $validator->errors()], 422);
        }

        $credentials = $request->only(['email', 'password']);
        if (Auth::attempt($credentials)) {
            $user = Auth::user();
            if (!$user->email_verified_at) {
                return response()->json(['errors' => 'Email not verified'], 401);
            }
            $token = $user->createToken('Laravel Password Grant Client')->accessToken;
            return response()->json(['token' => $token], 200);
        } else {
            return response()->json(['errors' => 'Email or password is incorrect'], 401);
        }
    }
}

Giải thích thêm về action login:

  1. user->createToken(‘Laravel Password Grant Client’)->accessToken;` và trả về kết quả thành công và token vừa tạo. Nếu đăng nhập không thành công, chúng ta trả về kết quả lỗi và mã lỗi 401.
  2. Nếu người dùng chưa xác nhận email, chúng ta cũng trả về kết quả lỗi và mã lỗi 401.
  3. Lưu ý: trong code trên, chúng ta đã sử dụng thư viện Illuminate\Support\Facades\Auth để sử dụng các hàm xác thực của Laravel. Bạn cũng có thể sử dụng các hàm xác thực trong thư viện Illuminate\Auth\AuthManager thay vì sử dụng các hàm xác thực trong Auth facade.

Với 3 API trên, bạn không cần phải yêu cầu user đăng nhập thành công trước khi có thể sử dụng chúng. Tuy nhiên, với Web Service API cập nhật mật khẩu, chúng ta cần yêu cầu người sử dụng đã đăng nhập thành công. Chúng ta thực hiện việc kiểm tra này thông qua token (Bearer Token) đã được cung cấp ở json trả về khi đăng nhập thành công qua api login().

Sử dụng Bearer Token trong RESTful Web Service

Để tạo action updatePassword trong UserController, bạn có thể sử dụng code sau:


public function changePassword(Request $request)
{
    // Validate the request
    $validator = Validator::make($request->all(), [
        'password' => 'required|string|min:6',
    ]);
    if ($validator->fails()) {
        return response()->json(['errors' => $validator->errors()], 422);
    }

    // Check if the request has a valid Bearer token
    if ($request->bearerToken()) {
        // Get the authenticated user
        $user = $request->user();
        // Update the user's password
        $user->password = bcrypt($request->password);
        $user->save();
        return response()->json(['message' => 'Password changed successfully'], 200);
    } else {
        // Return error if the request doesn't have a valid Bearer token
        return response()->json(['error' => 'Unauthorized'], 401);
    }
}

Trong action này, chúng ta sử dụng câu lệnh Validator::make để kiểm tra tính hợp lệ của dữ liệu được gửi lên từ client. Nếu dữ liệu không hợp lệ, chúng ta trả về kết quả lỗi và mã lỗi 422.

Sau đó, chúng ta sử dụng hàm $request->bearerToken() để kiểm tra xem API call có chứa Bearer token hay không. Nếu có, chúng ta lấy thông tin người dùng hiện tại từ biến $request->user(). Sau đó, chúng ta cập nhật mật khẩu mới cho người dùng bằng câu lệnh $user->password = bcrypt($request->password) và lưu lại thông tin người dùng bằng câu lệnh $user->save(). Cuối cùng, chúng ta trả về kết quả thành công và mã lỗi 200.

Nếu API call không chứa Bearer token, chúng ta trả về lỗi 401 cho user.

Để yêu cầu api call phải có bearer token, bạn có thể thêm middleware auth:api vào route của action changePassword trong file routes/api.php như sau:

Route::put('/user/change-password', 'App\Http\Controllers\UserController@changePassword')->middleware('auth:api');

Khai báo các route cho app

Để khai báo route cho các action trên, bạn có thể sử dụng code sau trong tệp routes/api.php của Laravel:


<?php 
use Illuminate\Http\Request; 
use Illuminate\Support\Facades\Route; 
use App\Http\Controllers\UserController; 
/* |-------------------------------------------------------------------------- | API Routes |-------------------------------------------------------------------------- | | Here is where you can register API routes for your application. These | routes are loaded by the RouteServiceProvider within a group which | is assigned the "api" middleware group. Enjoy building your API! | */ 

Route::post('user/register', 'App\Http\Controllers\UserController@register'); 
Route::post('user/verify', 'App\Http\Controllers\UserController@verify'); 
Route::post('user/authenticate', 'App\Http\Controllers\UserController@authenticate'); 
Route::post('user/password', 'App\Http\Controllers\UserController@updatePassword'); 
Route::post('user/login', 'App\Http\Controllers\UserController@login'); 
Route::get('login', 'App\Http\Controllers\UserController@login'); 

Route::get('/user/{id}', 'App\Http\Controllers\UserController@getUser')->middleware('auth:api');
Route::put('/user/change-password', 'App\Http\Controllers\UserController@changePassword')->middleware('auth:api');

Trong đoạn code trên, chúng ta đã khai báo các route cho các action register, verify, authenticateupdatePassword.

Đối với action changePassword, chúng ta đã khai báo nó trong 1 Route::group với middlewareauth:api, để yêu cầu API call phải có Bearer token hợp lệ mới có thể gọi đến action này.

Chạy kiểm thử RESTful Web Service API

Đăng ký người dùng mới:


curl -X POST \
  http://localhost:8000/api/user/register \
  -H 'Content-Type: application/json' \
  -d '{
  "name": "test",
	"email": "user@example.com",
	"password": "password123",
  "password_confirmation: "password123"
}'

Xác nhận người dùng qua email:


curl -X POST \
  http://localhost:8000/api/user/verify \
  -H 'Content-Type: application/json' \
  -d '{
	"email": "user@example.com",
	"verification_code": "123456"
}'

Đăng nhập người dùng:


curl -X POST \
  http://localhost:8000/api/user/authenticate \
  -H 'Content-Type: application/json' \
  -d '{
	"email": "user@example.com",
	"password": "password"
}'

Thay đổi mật khẩu người dùng (yêu cầu Bearer token hợp lệ):


curl -X POST \
  http://localhost:8000/api/user/password \
  -H 'Authorization: Bearer ' \
  -H 'Content-Type: application/json' \
  -d '{
	"password": "newpassword"
}'

Bạn cũng có thể tìm hiểu cách sử dụng Postman cho việc chạy thử RESTful Web Service API của Laravel. Tham khảo cách cài đặt Postman tại đây.

Exit mobile version