Odoo自定义API设置auth="user"却返回登录页问题求助
auth="user"却重定向到登录页的原因及解决办法 我正在Odoo 15中开发自定义API,遇到API端点返回Odoo登录页而非预期响应的问题。已手动实现Basic Authentication,但认证未按预期工作,希望使用auth="user"而非auth="public"。
相关代码
# -*- coding: utf-8 -*- from odoo import http from odoo.http import request class ReadApi(http.Controller): @http.route("/api/test", methods=["GET"], type="http", auth="user", csrf=False) def test_api(self): try: auth_header = request.httprequest.headers.get('Authorization') if not auth_header: return "Missing Authorization ." if not auth_header.startswith("Basic "): return "Invalid auth type must be (basic auth)." Authorization = auth_header.split(' ') if Authorization == "YWRtaW46YWRtaW4=": return "valid Authorization" else: return "Invalid Authorization check username or password." except Exception as error: return error
测试情况
使用Postman发送GET请求至http://localhost:8069/api/test,请求头包含Authorization: Basic YWRtaW46YWRtaW4=,预期收到"Valid Authorization"响应,实际却被重定向到Odoo登录页。
环境:本地开发(Windows/Linux、Docker等)
重定向原因
当设置auth="user"时,Odoo会在请求到达你的视图函数之前,先触发自身的内置认证机制。只有通过Odoo官方认证流程的请求,才会进入你编写的代码逻辑。你手动解析Authorization头的代码根本没机会执行——因为Odoo检测到请求未通过它的认证,直接就重定向到登录页了。
另外你的代码存在语法错误:auth_header.split(' ')会返回一个列表(例如["Basic", "YWRtaW46YWRtaW4="]),你却将其与字符串"YWRtaW46YWRtaW4="做相等判断,这一逻辑永远不会成立,但在当前场景下这个错误还没到触发阶段。
调整方案
方案1:利用Odoo内置Basic Auth支持(推荐)
Odoo本身已经原生支持Basic Authentication,无需手动解析请求头,只需保持auth="user",并确保请求传递的是Odoo系统内有效用户的账号密码(Base64编码)即可:
- 简化控制器代码,移除手动认证逻辑:
# -*- coding: utf-8 -*- from odoo import http from odoo.http import request class ReadApi(http.Controller): @http.route("/api/test", methods=["GET"], type="http", auth="user", csrf=False) def test_api(self): # 能执行到这里,说明已通过Odoo的user认证 return f"Valid Authorization for user: {request.env.user.login}"
- 在Postman中配置认证:
- 直接在Authorization选项卡选择Basic Auth,输入Odoo系统内存在的用户名和密码(如admin/admin),Postman会自动生成正确的请求头;
- 也可手动编码:将
admin:admin转换为Base64编码得到YWRtaW46YWRtaW4=,作为Authorization头的值传递。
方案2:自定义认证(脱离Odoo用户体系)
如果不需要依赖Odoo内置用户,完全自定义认证逻辑,可将auth="none",自行控制整个认证流程:
# -*- coding: utf-8 -*- from odoo import http from odoo.http import request import base64 class ReadApi(http.Controller): @http.route("/api/test", methods=["GET"], type="http", auth="none", csrf=False) def test_api(self): try: auth_header = request.httprequest.headers.get('Authorization') if not auth_header: return request.make_response("Missing Authorization.", status=401) if not auth_header.startswith("Basic "): return request.make_response("Invalid auth type must be basic auth.", status=401) # 修复split后的取值错误 auth_part = auth_header.split(' ')[1] # 解码Base64 decoded = base64.b64decode(auth_part).decode('utf-8') username, password = decoded.split(':') # 替换为你的自定义认证逻辑 if username == "admin" and password == "admin": return "Valid Authorization" else: return request.make_response("Invalid Authorization check username or password.", status=401) except Exception as error: return request.make_response(str(error), status=500)
注意:使用auth="none"时,需确保自定义认证逻辑足够安全,防止未授权访问。
内容的提问来源于stack exchange,提问作者sarm

