webman (本地nginx反向代理域名 webman.lc)
react (vite, locahost:5173)
webman官方user插件
已經(jīng)成功配置了文檔中的 跨域中間件,get/post 請(qǐng)求除 session/cookie 外的數(shù)據(jù)都可以接收到,但是 session/cookie 獲取不到,做了最簡(jiǎn)單的測(cè)試文件,get 設(shè)置 session,post 獲取session,獲取不到,看 network 標(biāo)頭,未發(fā)送任何cookie,在響應(yīng)頭的 set-cookie 那邊會(huì)提示:此Set-Cookie標(biāo)頭未指定SameSite屬性,默認(rèn) SameSite=Lax
注:如果開啟 vite proxy,把請(qǐng)求地址換成 /api/,別的完全不動(dòng),就是成功的
下面寫了個(gè)簡(jiǎn)單的測(cè)試,session 為 null
// 測(cè)試接口: http://webman.lc/app/user/login/test
public function test(Request $request) {
if ($request->method() === 'POST') {
return json(['code' => 1, 'method' => 'POST', 'data' => [
'session_value' => session('test-value'),
'info' => $request->post()
]]);
} elseif ($request->method() === 'GET') {
$value = $request->get('value');
$request->session()->set('test-value', $value);
return json(['code' => 1, 'method' => 'GET', 'data' => [
'session' => session('test-value'),
'value' => $value
]]);
}
}
// 前端測(cè)試
import axios from 'axios';
axios.defaults.withCredentials = true;
// 請(qǐng)求標(biāo)頭:PHPSID=923c68b641a8d9418bd18b92151f7972
const testGet = async () => {
try {
// 發(fā)送 GET 請(qǐng)求
axios.get('http://webman.lc/app/user/login/test?value=loginTest', {
withCredentials: true
}).then((json) => console.log(json));
} catch (error) {
console.error('Error testing cookie:', error);
}
};
const testPost = async () => {
try {
// 發(fā)送 POST 請(qǐng)求
axios.post('http://webman.lc/app/user/login/test', {
username: 'adelle25@example.org',
password: '123123'
}).then((json) => console.log(json));
} catch (error) {
console.error('Error testing cookie:', error);
}
};
// testGet();
testPost();
export default () => {
return <div>Check console for cookie info</div>;
}
// 中間件 plugin/user/app/middleware/
<?php
namespace plugin\user\app\middleware;
use Webman\MiddlewareInterface;
use Webman\Http\Response;
use Webman\Http\Request;
class AccessControl implements MiddlewareInterface
{
public function process(Request $request, callable $handler) : Response
{
// 如果是options請(qǐng)求則返回一個(gè)空響應(yīng),否則繼續(xù)向洋蔥芯穿越,并得到一個(gè)響應(yīng)
$response = $request->method() == 'OPTIONS' ? response('') : $handler($request);
// 給響應(yīng)添加跨域相關(guān)的http頭
$response->withHeaders([
'Access-Control-Allow-Credentials' => 'true',
'Access-Control-Allow-Origin' => $request->header('origin', 'http://localhost:5173'),
'Access-Control-Allow-Methods' => $request->header('access-control-request-method', 'GET, POST, OPTIONS'),
'Access-Control-Allow-Headers' => $request->header('access-control-request-headers', 'Content-Type, Authorization, X-Requested-With'),
]);
return $response;
}
}
// 中間件配置 plugin/user/config/
<?php
use plugin\user\app\middleware\AccessControl;
return [
// 全局中間件
'' => [
// ... 這里省略其它中間件
AccessControl::class,
]
];
在前端 GET 請(qǐng)求設(shè)置 session 后,在 POST 請(qǐng)求獲取 session
會(huì)發(fā)現(xiàn) session 為 null
操作系統(tǒng):macos
webman + webman-admin 最新版
你的問題主要在于跨域請(qǐng)求時(shí)的 SameSite
屬性設(shè)置以及 withCredentials
的使用。
設(shè)置 SameSite
屬性:
在你的 webman
項(xiàng)目中,確保在設(shè)置 session
的地方添加 SameSite=None
和 Secure
屬性。例如:
use Webman\Http\Response;
use Webman\Http\Request;
return new Response(200, [
'Set-Cookie' => 'test-value=' . $value . '; Path=/; HttpOnly; SameSite=None; Secure'
]);
確保前后端都設(shè)置了 withCredentials
:
在你的前端代碼中,你已經(jīng)設(shè)置了 withCredentials
,確保在所有請(qǐng)求中都包含此設(shè)置。
axios.defaults.withCredentials = true;
修改 Nginx 配置:
確保你的 Nginx 配置中沒有阻止跨域請(qǐng)求,并且允許發(fā)送 credentials
:
server {
listen 80;
server_name webman.lc;
location / {
proxy_pass http://localhost:8787;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 允許跨域
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'Content-Type, Authorization, X-Requested-With';
}
}
確保 session
的正確設(shè)置:
在 Webman 中,確保 session
配置正確,并且在設(shè)置 session
時(shí)沒有遺漏 SameSite
屬性:
// 設(shè)置 session
$request->session()->set('test-value', $value);
// 獲取 session
$session_value = $request->session()->get('test-value');
檢查瀏覽器控制臺(tái):
打開瀏覽器控制臺(tái),檢查網(wǎng)絡(luò)請(qǐng)求的 Request Headers
和 Response Headers
,確保 Set-Cookie
頭包含 SameSite=None; Secure
屬性,并且請(qǐng)求頭包含 Cookie
。
確保 HTTPS:
如果你使用的是 SameSite=None
,需要確保你的站點(diǎn)使用 HTTPS,否則 Secure
屬性將無法生效。
通過以上步驟,應(yīng)該可以解決跨域請(qǐng)求時(shí) session
和 cookie
無法獲取的問題。
替你問的AI http://www.wtbis.cn/ai
謝謝,和chatgpt 4.o的回答一樣,但是不能解決問題,它甚至重復(fù)了nginx 與中間件里標(biāo)頭的設(shè)置。。。中間件、credentials 這些能查到的設(shè)置都設(shè)置了,也沒報(bào)錯(cuò),就是session獲取不到
排查了兩天了,就是沒辦法解決 T T
除了 withCredentials、跨域http頭外,還能怎么排查。。。
======
更新一下,似乎這些設(shè)置都是針對(duì)跨域請(qǐng)求,比如 a.site.com 與 b.site.com,我把前端訪問地址從 localhost:5173 修改成了 front.webman.lc:5173 , 就能順利獲取 session cookie 了
跨站的話,這些設(shè)置似乎還不夠,還需要 https 的相關(guān)配置?