首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

OAuth2.0 實戰:基於 ThinkPHP 搭建授權服務器完整示例

     編輯:PHP 相關知識

項目背景與準備

OAuth 2.0 是業界標準的授權協議,廣泛用於第三方登錄、API 開放平台。本文記錄如何在 ThinkPHP(以下簡稱 TP)框架中集成 bshaffer/oauth2-server-php 庫,快速構建一個包含「授權碼模式」與「客戶端憑證模式」的 OAuth2 服務端。

數據庫設計(MySQL)

執行以下 SQL 創建標準 OAuth2 數據表,包含:訪問令牌、授權碼、客戶端信息、公鑰、刷新令牌、作用域、用戶表。

-- oauth_access_tokens
CREATE TABLE `oauth_access_tokens` (
  `access_token` VARCHAR(255) NOT NULL,
  `client_id` VARCHAR(80) NOT NULL,
  `user_id` VARCHAR(80) DEFAULT NULL,
  `expires` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `scope` VARCHAR(2000) DEFAULT NULL,
  PRIMARY KEY (`access_token`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- oauth_authorization_codes
CREATE TABLE `oauth_authorization_codes` (
  `authorization_code` VARCHAR(255) NOT NULL,
  `client_id` VARCHAR(80) NOT NULL,
  `user_id` VARCHAR(80) DEFAULT NULL,
  `redirect_uri` VARCHAR(2000) DEFAULT NULL,
  `expires` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `scope` VARCHAR(2000) DEFAULT NULL,
  `id_token` VARCHAR(2000) DEFAULT NULL,
  PRIMARY KEY (`authorization_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- oauth_clients
CREATE TABLE `oauth_clients` (
  `client_id` VARCHAR(80) NOT NULL,
  `client_secret` VARCHAR(80) NOT NULL,
  `redirect_uri` VARCHAR(2000) NOT NULL,
  PRIMARY KEY (`client_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

INSERT INTO `oauth_clients` (`client_id`, `client_secret`, `redirect_uri`) VALUES
('demoapp', 'demopass', 'https://127.0.0.1/tp/index.php');

-- oauth_refresh_tokens
CREATE TABLE `oauth_refresh_tokens` (
  `refresh_token` VARCHAR(255) NOT NULL,
  `client_id` VARCHAR(80) NOT NULL,
  `user_id` VARCHAR(80) DEFAULT NULL,
  `expires` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `scope` VARCHAR(2000) DEFAULT NULL,
  PRIMARY KEY (`refresh_token`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- oauth_scopes
CREATE TABLE `oauth_scopes` (
  `scope` VARCHAR(255) NOT NULL,
  `is_default` TINYINT(1) DEFAULT NULL,
  PRIMARY KEY (`scope`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- oauth_users
CREATE TABLE `oauth_users` (
  `username` VARCHAR(255) NOT NULL,
  `password` VARCHAR(2000) DEFAULT NULL,
  `first_name` VARCHAR(255) DEFAULT NULL,
  `last_name` VARCHAR(255) DEFAULT NULL,
  PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

核心代碼結構

1. 基礎控制器 Org/OAuth2/Controller.php

封裝 PDO 存儲、Server 實例化、註冊 Grant Type(Authorization Code + Client Credentials)。

<?php
namespace Org\OAuth2;

class Controller
{
    protected $oauth_server;
    protected $oauth_storage;
    protected $oauth_request;
    protected $oauth_response;

    public function __construct()
    {
        $this->oauth_storage = new \OAuth2\Storage\Pdo([
            'dsn' => C('DSN'),
            'username' => C('USERNAME'),
            'password' => C('PASSWORD')
        ]);

        $this->oauth_server = new \OAuth2\Server($this->oauth_storage);
        $this->oauth_server->addGrantType(new \OAuth2\GrantType\ClientCredentials($this->oauth_storage));
        $this->oauth_server->addGrantType(new \OAuth2\GrantType\AuthorizationCode($this->oauth_storage));

        $this->oauth_request = \OAuth2\Request::createFromGlobals();
        $this->oauth_response = new \OAuth2\Response();
    }
}

2. 資源保護基類 Org/OAuth2/Resource.php

驗證 Access Token,自動拋出 401 錯誤。

<?php
namespace Org\OAuth2;

class Resource extends Controller
{
    protected $tokenData;

    public function __construct()
    {
        parent::__construct();
        if (!$this->oauth_server->verifyResourceRequest(\OAuth2\Request::createFromGlobals())) {
            $this->oauth_server->getResponse()->send();
            die;
        }
        $this->tokenData = $this->oauth_server->getResourceController()->getToken();
    }
}

3. 授權端點 Api/Controller/OAuth2Controller.php

<?php
namespace Api\Controller;

class OAuth2Controller extends \Org\OAuth2\Controller
{
    public function authorize()
    {
        if (!$this->oauth_server->validateAuthorizeRequest($this->oauth_request, $this->oauth_response)) {
            $this->oauth_response->send();
            die;
        }
        // 此處應展示用戶授權頁面,用戶確認後調用 handleAuthorizeRequest
        $this->oauth_server->handleAuthorizeRequest($this->oauth_request, $this->oauth_response, true);
        
        // 為演示直接返回 code
        $code = substr($this->oauth_response->getHttpHeader('Location'), strpos($this->oauth_response->getHttpHeader('Location'), 'code=') + 5, 40);
        echo json_encode(['code' => $code]);
    }

    public function token()
    {
        $this->oauth_server->handleTokenRequest(\OAuth2\Request::createFromGlobals())->send();
    }
}

4. 測試受保護資源 Api/Controller/TestController.php

<?php
namespace Api\Controller;

class TestController extends \Org\OAuth2\Resource
{
    public function test()
    {
        echo json_encode(['success' => true, 'message' => 'You accessed my APIs!']);
    }

    public function getToken()
    {
        echo json_encode(['token' => $this->tokenData]);
    }
}

配置文件 Conf/config.php

<?php
require_once VENDOR_PATH . '/OAuth2/Autoloader.php';
\OAuth2\Autoloader::register();

return [
    'DSN' => 'mysql:host=localhost;dbname=oauth2',
    'USERNAME' => 'root',
    'PASSWORD' => '',
    'AUTOLOAD_NAMESPACE' => ['OAuth2' => VENDOR_PATH . 'OAuth2/'],
];

測試流程

  1. 訪問 /api/oauth2/authorize?client_id=demoapp&redirect_uri=https://127.0.0.1/tp/index.php&response_type=code 獲取授權碼。
  2. 攜帶 code 請求 /api/oauth2/token 獲取 access_token。
  3. 攜帶 Authorization: Bearer <access_token> 訪問 /api/test/test 驗證資源保護。

避坑指南

  • 確保 redirect_uri 與客戶端註冊的一致,否則報 invalid_redirect_uri。
  • 生產環境務必使用 HTTPS,並妥善保管 client_secret。
  • 擴展場景:可添加 RefreshToken、JWT、Scope 細粒度權限控制。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved