【问题标题】:How to connect to Odoo database from an android application如何从 Android 应用程序连接到 Odoo 数据库
【发布时间】:2019-04-23 19:37:39
【问题描述】:

我正在开发一个 Android 应用程序,我想从 Odoo 服务器检索数据。

为此,我在 Odoo 中开发了一个自定义模块,并在其中创建了一个控制器。

我的控制器:

import json
import xmlrpc.client as xmlrpclib
from odoo import http
from openerp.http import Response

class resUserController(http.Controller):
    url = '<my url>'
    db = '<name of my database>'

    @http.route('/user/login', type='json', method='GET', auth='public')
    def get_login(self, **kwargs):
        username = kwargs.get('email')
        password = kwargs.get('password')
        common = xmlrpclib.ServerProxy('{}/xmlrpc/2/common'.format(self.url), allow_none=True)

        uid = common.authenticate(self.db, username, password, {})
        if uid:
            Response.status = '200 Succesful operation'
            json_result = {'token': uid}
            return json.dumps(json_result)
        Response.status = '400 Invalid credentials'
        return

当我从 python 脚本调用它来尝试它时,它工作正常,我得到一个 &lt;Response [200]&gt; 和一个带有我连接到的帐户 ID 的 json {u'jsonrpc': u'2.0', u'result': u'{"token": 8}', u'id': None}

但是我有另一个函数,我在同一个控制器中用另一个路由调用,但这次用auth='user',因为我希望用户只能看到他有权查看的信息。

@http.route('/user/getInfo', type='json', method='GET', auth='user')
def get_info(self, **kwargs):
    uid = 1
    password = '<my admin password>'
    models = xmlrpclib.ServerProxy('{}/xmlrpc/2/object'.format(self.url), allow_none=True)
    info = models.execute_kw(self.db, uid, password, 'res.users',
                             'search_read', [[['id', '=', kwargs.get('token')]]],
                             {'fields': ['info']})[0]['invite_code']
    if info:
        Response.status = '200 Succesful operation'
        json_result = {'info': info}
        return json.dumps(json_result)
    Response.status = '404 User not found'
    return

当我使用auth='public' 时,此功能运行良好,但当我使用auth='user' 时,我得到以下 json 响应:

响应 [200]

{  
    u'jsonrpc': u'2.0',   
    u'id': None,   
    u'error': {  
        u'message': u'Odoo Session Expired',   
        u'code': 100,  
        u'data': {  
            u'debug': u'Traceback (most recent call last):  
                      File "/usr/lib/python3/dist-packages/odoo/http.py", line 650, in _handle_exception  
                      return super(JsonRequest, self)._handle_exception(exception)  
                      File "/usr/lib/python3/dist-packages/odoo/http.py", line 310, in _handle_exception  
                      raise pycompat.reraise(type(exception), exception, sys.exc_info()[2])  
                      File "/usr/lib/python3/dist-packages/odoo/tools/pycompat.py", line 87, in reraise  
                      raise value  
                      File "/usr/lib/python3/dist-packages/odoo/addons/http_routing/models/ir_http.py", line 342, in _dispatch  
                      cls._authenticate(func.routing[\'auth\'])  
                      File "/usr/lib/python3/dist-packages/odoo/addons/base/ir/ir_http.py", line 117, in _authenticate  
                      getattr(cls, "_auth_method_%s" % auth_method)()  
                      File "/usr/lib/python3/dist-packages/odoo/addons/base/ir/ir_http.py", line 90, in _auth_method_user  
                      raise http.SessionExpiredException("Session expired")  
                      odoo.http.SessionExpiredException: Session expired',   
            u'exception_type': u'internal_error',   
            u'message': u'Session expired',   
            u'name': u'odoo.http.SessionExpiredException',  
            u'arguments': [u'Session expired'] 
        }  
    }  
}

我的工作基于This documentation,这是一个官方 Odoo 文档,但问题如下:

1它要求我在每个功能中写下我的管理员密码,这似乎很危险。

2 身份验证后,我得到了我的用户的 id,但没有 会话令牌。那么如何通过auth='user' 通知我的函数我已连接以及连接到哪个用户?

这是我的脚本来测试我的调用:

import requests
import json

url_connect = "<my url>/user/login"
url = "<my url>/user/getInfo"
headers = {'Content-Type': 'application/json'}
data_connect = {
                "params": {
                           "email": "<my test account email>",
                           "password": "<my test account password>",
                }
    }
data = {
        "params": {
                   "token": <my test account id>,
            }
       }
data_json = json.dumps(data)
r = requests.get(url=url_connect, data=json.dumps(data_connect), headers=headers)
print(r)
print(r.json())
r = requests.get(url=url, data=data_json, headers=headers)
print(r)
print(r.json())

【问题讨论】:

  • 我也尝试使用 odoo 的内置控制器“/web/session/authenticate”进行连接。它工作正常,并返回我一个会话 ID。但是我怎样才能使用这个 sessionID 呢?我会尝试将它传递给我的参数,但效果不佳,我仍然有“Odoo session expired”的相同答案

标签: python json python-3.x odoo odoo-11


【解决方案1】:

注意事项:

  • 切勿在 GET 请求中发送凭据
  • 所有 Odoo RPC 请求都是 POST 请求
  • 如果您使用 /web/session/authenticate,则不需要自定义登录路径
  • 外部 API 旨在在 odoo 框架之外使用。开发模块时,如果在模型中使用 self.env[''],如果在控制器中使用 http.request.env['']
  • /web/session/authenticate 的调用会返回一个包含 session_id 的 json,您必须将其在 cookies 中传递给后续请求,直到您调用 /web/session/destroy 退出。

这是一个使用 /web/session/auenticate 的示例:

import requests
import json

url_connect = "http://localhost:8069/web/session/authenticate"
url = "http://localhost:8069/web/session/get_session_info"

headers = {'Content-Type': 'application/json'}

data_connect = {
    "params": {
        "db": "demo1",
        "login": "admin",
        "password": "admin",
    }
}

data = {}

session = requests.Session()

r = session.post(url=url_connect, data=json.dumps(data_connect), headers=headers)

if r.ok:
    result = r.json()['result']

    if result.get('session_id'):
        session.cookies['session_id'] = result.get('session_id')

r = session.post(url=url, data=json.dumps(data), headers=headers)
print(r)
print(r.json())

要从您的控制器获取信息,您可以使用 request.env.user 来保存当前登录的用户,并且由于您指定 auth='user' 它必须是有效的。示例代码可能如下所示:

from odoo.http import request

class UserController(http.Controller):
  @http.route('/user/getInfo', type='json', method='POST', auth='user')
  def get_info(self, **kwargs):
    current_user = request.env.user

    Response.status = '200 Succesful operation'
    json_result = {'info': current_user.info}
    return json.dumps(json_result)

【讨论】:

    【解决方案2】:

    写得很好,你已经完成了作业。这让我能够使用 api 样式请求对移动用户会话进行身份验证。

    @http.route([
        '/m/login/email',
    ], type='http', auth="public", website=True, methods=["POST"], csrf=False)
    def users_login_email(self, **kwargs):
        if kwargs:
            data = json.loads(kwargs.keys()[0])
        else:
            data = json.loads(request.httprequest.data)
    
        email = data.get('email')
        password = data.get('password')
    
        if not request.session.db:
            setup_db()
        uid = request.session.authenticate(request.session.db, email, password)
        if uid:
            return self._user_details(uid)
        body = json.dumps({"body": ["Credenciales Incorrectas"]})
        return werkzeug.wrappers.Response(body, status=403, headers=[
            ('Content-Type', 'application/json'), ('Content-Length', len(body))
        ])
    

    另外,我没有使用auth='user' 来防止 Odoo 搞乱重定向和网络资料检查。我在需要经过身份验证的用户返回正确的 HTTP 错误状态代码的控制器路由中使用此注释包装器

    def check_user(f):
        @functools.wraps(f)
        def wrap(*args, **kwargs):
            if not request.session.db:
                setup_db()
    
            request.uid = request.session.uid
    
            if not request.uid:
                body = json.dumps({"body": ["Session Expired"]})
                return werkzeug.wrappers.Response(body, status=403, headers=[
                    ('Content-Type', 'application/json'), ('Content-Length', len(body))
                ])
    
            return f(*args, **kwargs)
    
        return wrap
    

    你可以这样使用它:

    @check_user
    @http.route([
        '/m/<int:shop_id>/cart/info',
    ], type='http', auth="public", website=True)
    def cart_info(self, shop_id, **kwargs):
    

    【讨论】:

    • 感谢没有基本 Odoo 的 http 重定向的解决方案。这可能会成为一个问题,如果是这样,我会尝试您的解决方案。
    猜你喜欢
    • 2011-07-12
    • 2018-10-23
    • 2020-05-16
    • 2016-10-04
    • 2014-05-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多