+1

M2M Authentication: Xây dựng API "Đăng nhập" tự động cho Xe Ô tô (Connected Car)

Khi nói đến "Đăng nhập", 99% anh em dev sẽ nghĩ ngay đến việc User gõ Email và Password. Nhưng trong thế giới của xe hơi kết nối (Connected Cars), cái xe ô tô không có tay để gõ bàn phím!

Đây là bài toán giao tiếp Machine-to-Machine (M2M). Chiếc xe sẽ tự động gửi thông số định danh của nó (thường là số khung - VIN) kèm theo một mã bí mật (Secret Key / Device Key) được nhà máy nạp sẵn vào chip hệ thống để lấy Token giao tiếp với Server Backend.

Hôm nay, anh em mình sẽ thiết kế luồng xác thực M2M cho Ô tô chuẩn Enterprise bằng Laravel, tách biệt hoàn toàn với luồng đăng nhập của User thông thường.

Lời mở đầu: Xe ô tô "đăng nhập" như thế nào?

Trong một hệ thống xe thông minh, bạn có 2 thực thể riêng biệt:

  1. Chủ xe (User): Đăng nhập bằng App trên điện thoại (Email/Password) để xem vị trí xe, bật tắt điều hòa.
  2. Chiếc xe (Vehicle): Tự động "đăng nhập" vào Server mỗi khi nổ máy để báo cáo tọa độ GPS, mức nhiên liệu, và nhận lệnh từ App.

Nếu bạn dùng chung bảng users cho cả Chủ xe và Chiếc xe, hệ thống của bạn sẽ trở thành một mớ bòng bong bảo mật. Chiếc xe cần một bảng riêng, một cơ chế cấp Token riêng biệt được gọi là Device Authentication.

Chúng ta sẽ dùng Laravel Sanctum để cấp API Token cho thiết bị, dựa trên mã VIN (Vehicle Identification Number) và Secret Key.

Bước 1: Khởi tạo dự án & Xây dựng "Móng" Database

Tạo một dự án hoàn toàn mới để không đụng chạm đến code cũ:

laravel new connected-car-backend
cd connected-car-backend

1. Tạo Model, Migration và Factory cho Vehicle (Xe ô tô)

php artisan make:model Vehicle -m -f

2. Thiết kế bảng vehicles:

Mở file migration vừa tạo lên. Chúng ta cần lưu Số khung (VIN) làm định danh duy nhất, và một đoạn Hash Secret Key (giống như mật khẩu của xe).

// database/migrations/xxxx_create_vehicles_table.php
public function up(): void
{
    Schema::create('vehicles', function (Blueprint $table) {
        $table->id();
        $table->string('vin_code', 17)->unique(); // Số khung ô tô chuẩn quốc tế dài 17 ký tự
        $table->string('secret_key'); // Băm mật mã (Hash) lưu trong chip của xe
        $table->string('model_name'); // VD: VF8, Tesla Model 3
        $table->string('firmware_version')->default('1.0.0');
        $table->boolean('is_active')->default(true); // Trạng thái hoạt động
        $table->timestamp('last_online_at')->nullable(); // Lần cuối xe kết nối
        $table->timestamps();
    });
}

Chạy lệnh php artisan migrate để tạo bảng.

3. Cấu hình Model Vehicle sử dụng Sanctum:

Mặc định Laravel Sanctum chỉ gắn vào model User. Chúng ta phải khai báo trait HasApiTokens cho xe ô tô để nó có quyền sinh Token.

// app/Models/Vehicle.php
namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Laravel\Sanctum\HasApiTokens; // CỰC KỲ QUAN TRỌNG

class Vehicle extends Model
{
    use HasFactory, HasApiTokens;

    protected $fillable = [
        'vin_code',
        'secret_key',
        'model_name',
        'firmware_version',
        'is_active',
        'last_online_at'
    ];

    // Giấu secret_key đi để không bao giờ bị lọt ra ngoài JSON response
    protected $hidden = [
        'secret_key',
    ];
}

Bước 2: Action Pattern - Xử lý logic Đăng nhập của Xe

Việc xe ô tô đăng nhập thực chất là kiểm tra VIN, đối chiếu Secret Key và nhả ra Token. Ta sẽ gói gọn nó vào một Action.

mkdir app/Actions

Tạo file app/Actions/AuthenticateVehicleAction.php:

namespace App\Actions;

use App\Models\Vehicle;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;

class AuthenticateVehicleAction
{
    public function execute(string $vinCode, string $plainSecretKey, string $firmwareVersion): array
    {
        // 1. Tìm xe dựa trên mã VIN
        $vehicle = Vehicle::where('vin_code', $vinCode)->first();

        // 2. Chặn các trường hợp lỗi (Không tìm thấy, Xe bị khóa, Sai khóa bí mật)
        if (!$vehicle || !$vehicle->is_active || !Hash::check($plainSecretKey, $vehicle->secret_key)) {
            // Dùng chung 1 thông báo lỗi để chống Hacker dò tìm VIN hợp lệ
            throw ValidationException::withMessages([
                'auth' => 'Thông tin xác thực xe không hợp lệ hoặc xe đã bị vô hiệu hóa.'
            ]);
        }

        // 3. Cập nhật thông tin phiên làm việc mới nhất
        $vehicle->update([
            'last_online_at' => now(),
            'firmware_version' => $firmwareVersion // Xe báo cáo luôn phiên bản phần mềm hiện tại
        ]);

        // 4. Xóa Token cũ của xe (Nếu sếp yêu cầu mỗi xe chỉ có 1 kết nối duy nhất tại 1 thời điểm)
        $vehicle->tokens()->delete();

        // 5. Cấp Token mới cho Device
        $token = $vehicle->createToken('Vehicle_IoT_Connection')->plainTextToken;

        return [
            'vehicle' => $vehicle,
            'access_token' => $token,
            'token_type' => 'Bearer',
        ];
    }
}

Bước 3: Controller Mỏng Nhẹ & Định tuyến

Tạo Controller để hứng Request bắn lên từ hệ thống nhúng (Embedded System) của ô tô.

php artisan make:controller Api/VehicleAuthController
// app/Http/Controllers/Api/VehicleAuthController.php
namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Actions\AuthenticateVehicleAction;

class VehicleAuthController extends Controller
{
    public function login(Request $request, AuthenticateVehicleAction $action)
    {
        // 1. Validate payload từ xe gửi lên
        $request->validate([
            'vin_code' => 'required|string|size:17', // Ép chuẩn 17 ký tự
            'secret_key' => 'required|string',
            'firmware_version' => 'required|string'
        ]);

        // 2. Gọi Action xử lý
        $result = $action->execute(
            $request->vin_code,
            $request->secret_key,
            $request->firmware_version
        );

        // 3. Trả kết quả về cho hệ thống nhúng của xe
        return response()->json([
            'success' => true,
            'message' => 'Xe đã kết nối mạng lưới thành công.',
            'data' => $result
        ], 200);
    }
}

Đăng ký Route tại routes/api.php:

use App\Http\Controllers\Api\VehicleAuthController;

Route::post('/iot/vehicle/auth', [VehicleAuthController::class, 'login']);

Bước 4: Tạo dữ liệu mẫu (Seeding) & Test bằng Postman

Trước khi test, ta phải đóng vai "Nhà máy sản xuất" để nạp thông tin một chiếc xe vào Database.

4.1. Tạo xe bằng Tinker Mở Terminal, chạy:

php artisan tinker

Copy và dán đoạn code này vào Tinker để sản xuất 1 chiếc xe:

use App\Models\Vehicle;
use Illuminate\Support\Facades\Hash;

Vehicle::create([
    'vin_code' => 'VF8A1234567890XYZ', // Số VIN giả lập
    'secret_key' => Hash::make('SuperSecretHardwareKey2026'), // Mã băm của khóa bí mật
    'model_name' => 'VF8 Plus',
    'is_active' => true
]);

4.2. Thử lửa bằng Postman (Đóng vai chiếc xe gửi request)

Bật server Laravel: php artisan serve (Chạy ở cổng 8000).

Mở Postman, setup một Request như sau:

  1. Method: POST
  2. URL: [http://127.0.0.1:8000/api/iot/vehicle/auth](http://127.0.0.1:8000/api/iot/vehicle/auth)
  3. Headers: Accept: application/json
  4. Body (raw - JSON): (Giả lập chiếc xe nổ máy và bắt đầu kết nối với Backend)
{
    "vin_code": "VF8A1234567890XYZ",
    "secret_key": "SuperSecretHardwareKey2026",
    "firmware_version": "v2.1.4-stable"
}

Nhấn SEND và tận hưởng thành quả:

{
    "success": true,
    "message": "Xe đã kết nối mạng lưới thành công.",
    "data": {
        "vehicle": {
            "id": 1,
            "vin_code": "VF8A1234567890XYZ",
            "model_name": "VF8 Plus",
            "firmware_version": "v2.1.4-stable",
            "is_active": 1,
            "last_online_at": "2026-05-05T09:30:00.000000Z",
            "created_at": "2026-05-05T09:00:00.000000Z",
            "updated_at": "2026-05-05T09:30:00.000000Z"
        },
        "access_token": "1|PqRzT9...SanctumDeviceTokenHere",
        "token_type": "Bearer"
    }
}

Từ khoảnh khắc này, hệ thống máy tính trên ô tô sẽ lưu trữ cái access_token kia vào bộ nhớ RAM cục bộ của nó. Mỗi khi xe chạy, nó sẽ dùng token này để bắn tọa độ GPS lên Server (VD: API POST /api/iot/vehicle/telemetry) một cách bảo mật tuyệt đối, hoàn toàn tách biệt với quyền hạn của người lái xe!

Tóm lại

Hệ thống IoT hay Connected Cars nghe có vẻ vĩ mô, nhưng nền tảng của nó vẫn là sự vận dụng thông minh các mẫu thiết kế phần mềm (Design Patterns) và hiểu rõ bản chất của định danh thiết bị. Việc tách biệt User Auth và Device Auth (M2M) đảm bảo hệ thống của bạn chịu tải độc lập, dễ dàng phân quyền và bảo mật ở mức độ Enterprise.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí