Odoo 使用 cookie 来携带 session_id, session id 是一个哈希值,在 odoo/http.py setup session 之中可以看到,除了通过 cookie 携带,还可以通过请求的参数携带,或者 http header 中携带 session id。这里只讨论使用 cookie 携带 session id 的情形。
def setup_session(self, httprequest):
# recover or create session
session_gc(self.session_store)
sid = httprequest.args.get('session_id')
explicit_session = True
if not sid:
sid = httprequest.headers.get("X-Openerp-Session-Id")
if not sid:
sid = httprequest.cookies.get('session_id')
explicit_session = False
if sid is None:
httprequest.session = self.session_store.new()
else:
httprequest.session = self.session_store.get(sid)
return explicit_session
session id 会对应一个文件存在于文件系统之中,如果在 Linux 中,并且没有特意配置过,在 ~/.local/share/Odoo Product Name/下面,Odoo Product Name 是产品名称是可以配置的,这个目录实际上是 Odoo 默认的 data dir。如果启动的时候指定 data dir,session 存储的位置也会改变。data dir 下面 filestore 目录,存储 Odoo 文件(按照数据库名称不同再分一层目录),曾经有朋友问过,Odoo 的文件存数据库吗,大概率不是的,文件一般存在这里。
session id 对应的文件里面存储真正的 session 信息,主要是用户 id,数据库,用户语言等等一些用户的上下文信息。如果系统有这个上下文信息说明用户正在和系统对话,并且已经获得了系统的认证,不需要用户每次执行操作都提供用户名和密码重新获得授权。
session 的建立过程就是用户登录过程,用户登录成功即获得了一个有效的 session 存于 Odoo 的后台系统;当然任何非法的访问,肯定是无法取得一个 session 的,如果能取得 session 就是合法访问。
Odoo 用户在登录系统的时候会要求数据用户名和密码,有的还要求提供数据库名称。用户名密码通过表单 POST 到 web/login,web/login 同时支持 GET 和 POST,GET 就是返回 HTML 页面,POST 就是提交用户名密码验证用户。
POST 登录表单的时候必须要提供一个 csrf token,这个是 Odoo 的一个增强的安全机制。csrf token 是通过 GET web/login 这个页面的时候,Odoo 后台生成写到网页表单的隐藏 input 里面。这样当用户 POST 表单的时候会把csrf token携带过来。
csrf token 有两种,一种是包含最大时间戳的,就是说这个 token 会过期,登录的时候使用的 csrf token 就是有时间戳要求的。而其他 Odoo http 请求都是不用携带时间戳的 csrf token。携带时间戳的 csrf token 一般通过后台生成 html 的时候写成隐藏 input 元素放在表单里面;不带时间戳的 token 会通过 odoo 这个全局的 js 对象获取(后台生成 js 代码)。比如下载一个系统的图片或者附件都是需要这个csrf token 的这个token 就不需要 max ts (时间戳)。
如果 POST web/login 成功,Odoo 会发送一个重定位请求,让前端浏览器访问 web/,这时候同时 set 了 cookie 其中就包含了授权的 session id,这样再请求 web,Odoo 后台就给前端设置好一个 odoo js 对象并且包含了 session 信息,即前端的 js 可以直接通过 odoo js 对象访问到 session 对象。
重定向成功后,就可以进行授权操作了,所有的 Odoo Jsonrpc ,都能正常执行了。当然每次请求要带上 设置了 session id 的 Cookie;要求提供 csrf token 的api 还要提供csrf token,很多 api 不要求 csrf token,是否要求看看 controller 中的接口装饰,默认是要求提供。
@http.route('/web/database/create', type='http', auth="none", methods=['POST'], csrf=False)
def create(self, master_pwd, name, lang, password, **post):
try: ....
指定了 False 就是不要求。上边的创建数据库操作就是不要求提供 csrf token。
@http.route('/web/binary/upload_attachment', type='http', auth="user")
@serialize_exception
def upload_attachment(self, callback, model, id, ufile):
files = request.httprequest.files.getlist('ufile')
Model = request.env['ir.attachment']
out = """"""
args = []
而这个上传 attachment 的操作就必须要提供 csrf token,注意的是 csrf token 必须要通过表单参数提交。JSONRPC 没有 csrf token 的需要。
退出系统应该不用介绍了吧。自己找找看吧 !