Làm việc với AI

Dùng bản tóm tắt tối ưu cho ChatGPT, Claude, Grok hoặc Cursor.

Mở bản Markdown cho AI
Hãy đọc docs/AI-CONTEXT.md trước và tích hợp ứng dụng hiện tại với PHP SSO Service theo OAuth 2.0 Authorization Code Flow và OpenID Connect. Kiểm tra framework và session system của ứng dụng client; triển khai login route, callback route, state validation, PKCE nếu là public client, token exchange, UserInfo request và tạo session nội bộ. Dùng biến môi trường cho SSO_BASE_URL, CLIENT_ID, CLIENT_SECRET và REDIRECT_URI. Không sửa source code của SSO Service, không commit hoặc log secret/token, không thay đổi OAuth contract, và bổ sung hướng dẫn cấu hình cùng kiểm thử.
Tài liệu Bắt Đầu Nhanh

Khởi Động Nhanh

Hướng dẫn từng bước tích hợp luồng ủy quyền đăng nhập OAuth 2.0 vào ứng dụng của bạn.

Bước 1: Đăng Ký Ứng Dụng Khách

Truy cập vào Bảng điều khiển Nhà phát triển để đăng ký ứng dụng mới:

  1. Nhập tên ứng dụng của bạn.
  2. Điền danh sách Redirect URIs hợp lệ (ví dụ: https://yourapp.com/callback.php).
  3. Chọn loại Client: Bỏ chọn ô Public Client nếu bạn đang phát triển ứng dụng có backend bí mật (Confidential Client).
  4. Sau khi tạo, lưu trữ cẩn thận client_id và client_secret.

Bước 2: Cài Đặt và Cấu Hình

Bạn có thể sử dụng thư viện tiêu chuẩn hoặc triển khai trực tiếp bằng cURL / HTTP client. Ví dụ với thư viện PHP League OAuth2 Client:

composer require thephpleague/oauth2-client

Tạo tệp cấu hình config.php:

<?php
require_once __DIR__ . '/vendor/autoload.php';

define('SSO_SERVER_URL', 'https://accounts.lequangkhai.id.vn');
define('OAUTH_CLIENT_ID', 'your_client_id_here');
define('OAUTH_CLIENT_SECRET', 'your_client_secret_here');
define('OAUTH_REDIRECT_URI', 'https://yourapp.com/callback.php');

session_start();

Bước 3: Khởi Tạo Yêu Cầu Ủy Quyền

Khi người dùng chọn đăng nhập, tạo chuỗi ngẫu nhiên state và chuyển hướng trình duyệt đến endpoint ủy quyền:

<?php
// login.php
require_once __DIR__ . '/config.php';

use League\OAuth2\Client\Provider\GenericProvider;

$provider = new GenericProvider([
    'clientId'                => OAUTH_CLIENT_ID,
    'clientSecret'            => OAUTH_CLIENT_SECRET,
    'redirectUri'             => OAUTH_REDIRECT_URI,
    'urlAuthorize'            => SSO_SERVER_URL . '/authorize',
    'urlAccessToken'          => SSO_SERVER_URL . '/api/token',
    'urlResourceOwnerDetails' => SSO_SERVER_URL . '/api/userinfo'
]);

// Tạo state để chống tấn công CSRF
$_SESSION['oauth2state'] = $provider->getRandomState();

$authorizationUrl = $provider->getAuthorizationUrl([
    'scope' => ['openid', 'profile', 'email']
]);

header('Location: ' . $authorizationUrl);
exit;

Bước 4: Xử Lý Phản Hồi Callback

Sau khi người dùng đồng ý cấp quyền trên màn hình SSO, hệ thống sẽ chuyển hướng về redirect_uri kèm mã code và state:

<?php
// callback.php
require_once __DIR__ . '/config.php';

use League\OAuth2\Client\Provider\GenericProvider;

$provider = new GenericProvider([
    'clientId'                => OAUTH_CLIENT_ID,
    'clientSecret'            => OAUTH_CLIENT_SECRET,
    'redirectUri'             => OAUTH_REDIRECT_URI,
    'urlAuthorize'            => SSO_SERVER_URL . '/authorize',
    'urlAccessToken'          => SSO_SERVER_URL . '/api/token',
    'urlResourceOwnerDetails' => SSO_SERVER_URL . '/api/userinfo'
]);

// Kiểm tra tính toàn vẹn của tham số state
if (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) {
    unset($_SESSION['oauth2state']);
    die('Lỗi bảo mật: Tham số state không khớp (nguy cơ CSRF).');
}

try {
    // Đổi authorization code lấy Access Token
    $accessToken = $provider->getAccessToken('authorization_code', [
        'code' => $_GET['code']
    ]);

    // Gọi endpoint userinfo để lấy dữ liệu người dùng
    $resourceOwner = $provider->getResourceOwner($accessToken);
    $userProfile = $resourceOwner->toArray();

    // Lưu phiên đăng nhập người dùng vào session của ứng dụng
    $_SESSION['auth_user'] = [
        'id'       => $userProfile['sub'],
        'email'    => $userProfile['email'],
        'username' => $userProfile['username'],
        'name'     => $userProfile['name'] ?? $userProfile['username']
    ];
    $_SESSION['access_token'] = $accessToken->getToken();

    header('Location: /dashboard.php');
    exit;

} catch (\Exception $e) {
    die('Xác thực không thành công: ' . $e->getMessage());
}

Bước 5: Bảo Vệ Tuyến Đường Ứng Dụng

Tạo middleware hoặc tệp kiểm tra phiên để giới hạn truy cập cho các trang yêu cầu đăng nhập:

<?php
// auth-check.php
session_start();

if (!isset($_SESSION['auth_user'])) {
    header('Location: /login.php');
    exit;
}
Lưu Ý Về Triển Khai
  • Không công khai client_secret trên giao diện frontend hoặc mã nguồn client.
  • Trong môi trường chạy thật, cấu hình cookie phiên ở chế độ HttpOnly và Secure (HTTPS).
  • Sử dụng refresh_token để tự động làm mới access token khi nhận mã trạng thái HTTP 401.
Cập nhật gần nhất: Tháng 10, 2025
Lên đầu trang