PHP示例

PHP 示例(原生 + cURL,无框架依赖)

php运行

<?php
/**
 * 软柠通行证 OAuth 2.0 PHP 接入示例
 * 依赖:PHP 7.4+、cURL 扩展
 */

// 配置信息(替换为你的实际值)
define('CLIENT_ID', 'YOUR_CLIENT_ID');
define('CLIENT_SECRET', 'YOUR_CLIENT_SECRET');
define('REDIRECT_URI', 'https://your-domain.com/callback');
define('AUTH_URL', 'https://id.rutno.com/rn-oauth/authorize');
define('TOKEN_URL', 'https://id.rutno.com/rn-oauth/token');
define('USERINFO_URL', 'https://id.rutno.com/rn-oauth/userinfo');

// 步骤1:生成授权链接(引导用户授权)
function getAuthUrl() {
    // 生成随机state防CSRF
    $state = bin2hex(random_bytes(16));
    // 存储state到session(验证回调时使用)
    session_start();
    $_SESSION['oauth_state'] = $state;
    
    $params = [
        'client_id' => CLIENT_ID,
        'redirect_uri' => REDIRECT_URI,
        'response_type' => 'code',
        'scope' => 'username email avatar',
        'state' => $state
    ];
    
    return AUTH_URL . '?' . http_build_query($params);
}

// 步骤2:回调处理(获取code并换token)
function handleCallback() {
    session_start();
    
    // 1. 校验state防CSRF
    if (empty($_GET['state']) || $_GET['state'] !== $_SESSION['oauth_state']) {
        die('State验证失败,可能是CSRF攻击');
    }
    
    // 2. 处理错误
    if (!empty($_GET['error'])) {
        die('授权失败:' . $_GET['error'] . ' - ' . $_GET['error_description']);
    }
    
    // 3. 获取code
    if (empty($_GET['code'])) {
        die('未获取到授权码');
    }
    $code = $_GET['code'];
    
    // 4. 换取access_token
    $token = getAccessToken($code);
    if (!$token) {
        die('获取Token失败');
    }
    
    // 5. 获取用户信息
    $userInfo = getUserInfo($token['access_token']);
    if (!$userInfo) {
        die('获取用户信息失败');
    }
    
    // 6. 业务处理(示例:打印用户信息)
    print_r($userInfo);
}

// 换取Access Token
function getAccessToken($code) {
    $postData = [
        'grant_type' => 'authorization_code',
        'client_id' => CLIENT_ID,
        'client_secret' => CLIENT_SECRET,
        'code' => $code,
        'redirect_uri' => REDIRECT_URI
    ];
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, TOKEN_URL);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Content-Type: application/x-www-form-urlencoded'
    ]);
    // 开启HTTPS验证(生产环境必须)
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    if ($httpCode !== 200) {
        error_log('Token请求失败,HTTP状态码:' . $httpCode);
        return false;
    }
    
    $result = json_decode($response, true);
    if (json_last_error() !== JSON_ERROR_NONE || empty($result['access_token'])) {
        error_log('Token解析失败:' . $response);
        return false;
    }
    
    return $result;
}

// 获取用户信息
function getUserInfo($accessToken) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, USERINFO_URL);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: Bearer ' . $accessToken
    ]);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    if ($httpCode !== 200) {
        error_log('用户信息请求失败,HTTP状态码:' . $httpCode);
        return false;
    }
    
    $result = json_decode($response, true);
    if (json_last_error() !== JSON_ERROR_NONE) {
        error_log('用户信息解析失败:' . $response);
        return false;
    }
    
    return $result;
}

// 入口逻辑
if (!isset($_GET['code'])) {
    // 未获取到code,跳转到授权页
    header('Location: ' . getAuthUrl());
} else {
    // 回调处理
    handleCallback();
}
?>

PHP 使用说明

  1. 确保开启 session、curl、openssl 扩展
  2. 生产环境建议增加:Token 过期自动刷新(使用 refresh_token)接口请求超时设置日志持久化存储