这次的这个问题真的困扰了我 4 天. 不过最后还是解决了.
业务场景
我在 frappe 的服务端有 2 个服务, 都是 frappe 标准的服务, 一个是 /api/method/login, 一个是 /api/method/frappe.auth.get_logged_user。
这 2 个服务其实就是完成一次最基本的 Frappe 登录过程。 先通过 username,password 发往服务端做验证。校验通过, 则服务端会生成一个 session。
那么如果通过第 2 个 API 能获取登录的 session 用户名, 则代表登录完成。
1. 正常场景
第一步: 在浏览器里头,或者 postman 里头, 调用了 /api/method/login 的 post 方法, 是能得到正常登陆的.
第二步: 当第一步执行完成, 则再调用 /api/method/frappe.auth.get_logged_user, 我也能得到正常的结果, 请求状态是 200.
2. 正常场景
第一步, 我在 curl 里头, 调用 /api/method/login 的 post 方法, 是能得到正常登陆的.
# 使用 curl 登录并保存 cookie 和 CSRF token
curl -c cookies.txt -X POST https://foodxz.frappe.cloud/api/method/login \
-H "Content-Type: application/json" \
-d '{"usr": "goodhawk1@gmail.com", "pwd": "Hhshd&6363hgdj_"}' \
-i
复制代码
第二步, 当第一步执行完成, 则再调用 /api/method/frappe.auth.get_logged_user, 我将得到正常的结果
[root@zdevhost Temp]# curl -b cookies.txt -X GET https://foodxz.frappe.cloud/api/method/frappe.auth.get_logged_user \
> -H "Content-Type: application/json" \
> -i
HTTP/1.1 200 OK
Date: Mon, 02 Sep 2024 13:16:01 GMT
Content-Type: application/json
Content-Length: 33
Connection: keep-alive
Vary: Accept-Encoding
Set-Cookie: sid=74d88ddfccd063fc1ba7568a84bf7be904ea6c152a4ff2ab243c4725; Expires=Mon, 09 Sep 2024 15:16:01 GMT; Max-Age=612000; xxxx
复制代码
3. 不正常场景.
第一步, 我在 next.js 里头或者 curl 里头, 调用 /api/method/login 的 post 方法, 是能得到正常登陆的.
第二步, 当第一步执行完成, 则再调用 /api/method/frappe.auth.get_logged_user, 我将得不到结果. 返回的结果是 403 FORBIDDEN,
然后我可以看到服务端的 web.log 里头返回如下的内容
File "apps/frappe/frappe/model/db_query.py", line 114, in execute self.check_read_permission(self.doctype, parent_doctype=parent_doctype) File "apps/frappe/frappe/model/db_query.py", line 511, in check_read_permission self._set_permission_map(doctype, parent_doctype) File "apps/frappe/frappe/model/db_query.py", line 517, in _set_permission_map frappe.has_permission( File "apps/frappe/frappe/__init__.py", line 1090, in has_permission raise frappe.PermissionError frappe.exceptions.PermissionError
复制代码
解决方法是:
对第一个服务产生的 cookies 不直接回传到客户端。 需要手动去维护 cookies。手动维护的 cookies 只要 Key 和 Value, 不需要设置 options。
const res = await fetch('/api/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
credentials: 'omit',
mode: 'cors', // 可选参数,指定请求的模式,跨域请求需要设置为'cors'
cache: 'no-cache', // 可选参数,指定请求的缓存模式
redirect: 'follow', // 可选参数,指定重定向的模式
referrerPolicy: 'no-referrer', // 可选参数,指定referrer信息的政策
body: JSON.stringify({
username: username,
password: password
}),
});
if (!res.ok) throw new Error('Failed to fetch data');
const result = await res.json();
console.log('data', result);
await saveCookieSid(result.cookies[0]);
// 设置 cookies
await setCookies(result.serializedCookies);
复制代码
评论