我的场景如下:我的移动应用程序向外部网站发送一个请求,请求授权接收授权码,该授权码被发送到重定向URI以交换"访问令牌".我想将此令牌存储在Firebase实时数据库中,但使用通过我的应用程序发出该请求的用户的唯一用户ID.原因是,可能有多个用户向网站发出该请求,当然我需要将他们分开,包括安全存储令牌.没有UUID,一切都会正常工作,令牌将保存到Firebase.

我现在已经开始更新我的代码.虽然使用了OAuth 2.0,但是第三方Wesbit没有设置状态管理,所以我不能只传递编码的UUID,因为服务器只返回授权码.因此,我编写了一个脚本(store Uuid.php),它接收编码的UUID,对其进行解码,并将其保存在计时Cookie中,以便同一域(auth.example.com)上的其他脚本可以访问和使用该Cookie.服务器上还有第二个脚本(redirect.php),它由对第三方网站的授权请求触发,接收授权码,并应将其交换为访问令牌.然而,在此之前,它应该访问cookie并提取UUID.但是,它总是抛出{Error:UUID Not Found in the Cookie}.

<?php
// storeUuid.php
session_start();
// Function to return JSON response
function jsonResponse($data) {
    header('Content-Type: application/json');
    echo json_encode($data);
}

// Function to log errors
function logError($message) {
    error_log("Error: $message");
}

session_set_cookie_params([
    'lifetime' => 3600,
    'path' => '/', 
    'domain' => 'auth.example.com', 
    'secure' => true,
    'httponly' => true,
    'samesite' => 'None' 
  ]);

// Function to store UUID in session and cookie
function storeUUID($encodedUUID) {
    $decodedUUID = base64_decode($encodedUUID);
    
    if ($decodedUUID) {
        $_SESSION['userUid'] = $decodedUUID;
        setcookie("decodedUUID", $decodedUUID, time()+3600, "/", "auth.example.com"); 
        jsonResponse(["success" => "UUID stored in session and cookie.", "decodedUUID" => htmlspecialchars($decodedUUID), "sessionId" => session_id(), "cookie" => ($_COOKIE)]);
    } else {
        logError("No UUID provided or decoding failed.");
        jsonResponse(["error" => "No UUID provided or decoding failed.", "sessionId" => session_id()]);
    }
}

// Check if the request method is POST
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $data = json_decode(file_get_contents('php://input'), true);
    $encodedUUID = isset($data['encodedUserUid']) ? $data['encodedUserUid'] : null;

    if ($encodedUUID) {
        storeUUID($encodedUUID);
    } else {
        logError("No encoded UUID provided in POST request.");
        jsonResponse(["error" => "No encoded UUID provided in POST request.", "sessionId" => session_id()]);
    }
} else {
    logError("Invalid request method.");
    jsonResponse(["error" => "Invalid request method.", "sessionId" => session_id()]);
}
?>
<?php
// redirect.php
session_start();
require __DIR__.'/vendor/autoload.php';

use Kreait\Firebase\Factory;
use Kreait\Firebase\Exception\FirebaseException;

$serviceAccountPath = __DIR__.'/1234ABCD.json';
$databaseUrl = 'https://fundraiser-application-example.com';

function jsonResponse($data) {
    header('Content-Type: application/json');
    echo json_encode($data);
}

// Function to log errors
function logError($message) {
    error_log("Error: $message");
}

// Retrieve the decoded UUID from the cookie
if (isset($_COOKIE['decodedUUID'])) {
    $decodedUUID = $_COOKIE['decodedUUID'];
} else {
    logError("UUID not found in the cookie");
    jsonResponse(["error" => "UUID not found in the cookie"]);
    exit;
}

print_r($_COOKIE); 

if (!isset($_SESSION['userUid'])) {
    logError("User UID not found in session");
    jsonResponse(["error" => "User UID not found in session"]);
    exit;
}

try {
    $firebase = (new Factory)
        ->withServiceAccount($serviceAccountPath)
        ->withDatabaseUri($databaseUrl)
        ->createDatabase();
} catch (FirebaseException $e) {
    logError("Firebase Error: " . $e->getMessage());
    jsonResponse(["error" => "Firebase Error: " . $e->getMessage()]);
    exit;
} catch (Exception $e) {
    logError("General Error: " . $e->getMessage());
    jsonResponse(["error" => "General Error: " . $e->getMessage()]);
    exit;
}

$clientID = 'MY_CLIENT_ID';
$clientSecret = 'MY_SECRET_Key';
$tokenURL = 'https://auth.3rdparty.com/oauth/token';

if (isset($_GET['code'])) {
    $authorizationCode = $_GET['code'];
    $postData = http_build_query([
        'grant_type' => 'authorization_code',
        'client_id' => $clientID,
        'client_secret' => $clientSecret,
        'code' => $authorizationCode,
        'redirect_uri' => 'https://auth.example.com/redirect'
    ]);

    $context = stream_context_create([
        'http' => [
            'method' => 'POST',
            'header' => "Content-Type: application/x-www-form-urlencoded\r\n",
            'content' => $postData
        ]
    ]);

    $response = file_get_contents($tokenURL, false, $context);

    if ($response === FALSE) {
        logError("Error in token request");
        jsonResponse(["error" => "Error in token request"]);
        exit;
    }

    $responseData = json_decode($response, true);

    if (isset($responseData['access_token'])) {
        $accessToken = $responseData['access_token'];
        $userUid = $_SESSION['userUid'];

        $firebase->getReference('users/' . $userUid . '/example/access_token/')->set($accessToken);
        jsonResponse(["success" => "Access Token stored successfully for user", "userUid" => htmlspecialchars($userUid)]);
        
        $_SESSION = array();
        session_destroy();
    } else {
        logError("Access token not found in response or user UID not available in session");
        jsonResponse(["error" => "Access token not found in response or user UID not available in session", "response" => $responseData]);
    }
} else {
    logError("Authorization code not found");
    jsonResponse(["error" => "Authorization code not found"]);
}
?>

这就是那两份文件.如上所述,我从store Uuid.php获得的响应日志(log)显示,据我所知,一切都在运行:

LOG  Initiating OAuth process...
 LOG  Encoded user UID: ABCD1234
 LOG  Response from storeUuid.php: Array
(
    [decodedUUID] => BFM6OIHuCBe56s08cgcnmiEotff1
    [PHPSESSID] => lgh2gphfbbolcimv0abkkmrere
)
{"success":"UUID stored in session and cookie.","decodedUUID":"5678DCBA","sessionId":"my_session_id","cookie":{"decodedUUID":"5678DCBA","PHPSESSID":"my_session_id"}}
 LOG  Authorization URL: https://auth.3rdparty.com/oauth/authorize?response_type=code&client_id=(MY_CLIENT_ID)&redirect_uri=https://auth.example.com/redirect&scope=read
 LOG  OAuth URL opened successfully.

但我正在测试的应用程序的设备上的浏览器抛出了这个错误,它在cookie或会话中找不到UUID.

我在redirect.php中添加了print_r($_cookie);以查看cookie内容,但没有显示任何内容.

任何建议都会非常有帮助!

推荐答案

我通过使用定制的会话处理程序找到了一个解决方案.

class CustomSessionHandler implements SessionHandlerInterface {
    private $redis;

    public function open($savePath, $sessionName) {
        // Initialize the Redis connection
        $this->redis = new Redis();
        $this->redis->connect('127.0.0.1', 6379);
        return true;
    }

    public function close() {
        // Close the Redis connection
        $this->redis->close();
        return true;
    }

    public function write($id, $data) {
        $this->setSessionData($id, $data);
        return true;
    }

    public function read($id) {
        $data = $this->redis->hGet("session:$id", "data");
        return $data === false ? '' : $data;
    }    

    public function destroy($id) {
        // Attempt to delete the session data from Redis
        $result = $this->redis->del("session:$id");
        
        if ($result === false) {
            // Log the error or handle it accordingly
            error_log("Failed to delete session data for ID: $id");
            return false;
        }
        
        return true;
    }     

    public function gc($maxlifetime) {
        // Redis automatically handles expiration, so no need for manual garbage collection
        return 0;
    }

    public function setSessionData($id, $data) {
        // Set session data in your custom way
        $this->redis->hSet("session:$id", "data", $data);
        $this->redis->expire("session:$id", 600); // data expires after 10 minutes
    }

    public function getSessionData($id) {
        // Retrieve session data from Redis based on the session ID
        return $this->redis->hGet("session:$id", "data");
    }
}

// Register the custom session handler and start session
$handler = new CustomSessionHandler();
session_set_save_handler($handler, true);
session_start();

Php相关问答推荐

使用.htaccess将任何路由重定向到文件

如何在WooCommerce产品子类别中显示特定内容

返回WooCommerce中的所有已启用变体

如何从WooCommerce checkout 帐单邮箱字段中删除星号?

CKEDITOR-如何在PHP中判断提交后的空数据

Laravel Carbon DiffForHumans选项(年,月,天)

在 PHP 中将字符串分解为数组(字符串类似于 WP 短代码)

WooCommerce 中一件免费产品的数量折扣

如何在 Laravel 迁移中使用日期时间和天数?

Laravel 10 中的自定义类未找到

为什么 php 只能在我的 Nginx Web 服务器的某些目录中工作?

Firefox 115 会话行为:为什么页面无法找到要加载的现有会话 ID?

PHP header() 是否缓存重定向,如果是,如何防止它这样做?

为什么在 phpunit 的开头测试 PHP_VERSION?

转发和非转发呼叫 - 后期静态绑定

如何在 Laravel 9 中判断异常是否可报告?

使用php将图像上传到谷歌驱动器的问题

laravel 如何在添加 5 分钟后删除数据库数据?

doing_action() 函数阻止我的代码运行

从 csv 更新 WooCommerce 产品和变体库存