这次的这个问题真的困扰了我 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 tokencurl -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" \> -iHTTP/1.1 200 OKDate: Mon, 02 Sep 2024 13:16:01 GMTContent-Type: application/jsonContent-Length: 33Connection: keep-aliveVary: Accept-EncodingSet-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);
复制代码
评论