加载中…
个人资料
石家庄_老刘
石家庄_老刘
  • 博客等级:
  • 博客积分:0
  • 博客访问:36,592
  • 关注人气:29
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
相关博文
推荐博文
谁看过这篇博文
加载中…
正文 字体大小:

[转] 如何限制OpenERP用户的重复登录

(2014-06-07 11:06:15)
标签:

it

分类: openERP

How to restrict multiple logins of a user in OpenERP?


来自 http://www.zbeanztech.com/blog/how-restrict-multiple-logins-user-openerp-0

作者  Vinod_Kumar   提交时间   05/24/2011  

适用版本 OpenERP 6.x 

Hi all 。 recently I was assigned the task of restricting multiple logins of a single user in OpenERP. Since I'm a newbie to OpenERP, I searched the web for some kick-start articles but for vain. That is why I'm summarizing my points in this, my first ever, blog.

My task in hand was pretty straight forward – restrict a user from logging in from multiple locations simultaneously and for the time-being needs only to be implemented for the web-client. For this task I'm using OpenERP v6.0.2. So my first task was to find out how the web-client worked in OpenERP. While investigating I found that the web-client was powered by “CherryPy” (转载者附注: 在7.0 中, CherryPy 改为 WerkZeug了)

What is CherryPy?

This is the definition of CherryPy as in wikipedia.

"CherryPy is an object-oriented web application framework using the Python programming language. It is defined for rapid development of web applications by wrapping the HTTP protocol but stays at a low level and does not offer much more than what is defined in RFC 2616.”

A simple tutorial to get started with CherryPy can be found here:  【http://www.cherrypy.org/wiki/CherryPyTutorial】.  Going through this tutorial is highly recommended. (Some of you might have already got the idea about why I put the blog's title as “An Added Layer of Indirection” and for the rest go here. 【http://en.wikipedia.org/wiki/Indirection】)

How to retrieve data from cookies?

To get a cookie all we have to do is give the following:
  1. 
    cookie = cherrypy.response.cookie
    

 

By examining the cookie we can find that it contains session id and expiration date. We can retrieve all these details as follows:
  1. 
    session_id = cookie['session_id'].value
    
  2. 
    expiration_date = cookie['session_id']['expires']
    

 

Here keep a note that the expiration_date retrieved is a string and not a datetime object.

How to retrieve data from RPC session?

Another piece of information that we need is the user id of the logged in user. This data can be retrieved as follows:
  1. 
    uid = rpc.session.storage['uid']
    

 


A Simple Design

Keeping all these informations in mind a simple design was developed.
  1.  Store the session id and expiration date in the users table in the database.
  2. While logging in , check whether the user has already logged (If a user has already logged in then the session id will not be null).
  3. If the user is already logged in, check whether that session has expired.
  4. If the session has expired , allow the user to log in else consider it as multiple log in and cancel the log in.
  5. When the user is active,update the expiration date in the database.
  6. When the user logs out, clear the session id and expiration date fields in the database.
What Now?

Its now time to get our hands a little dirty, bear with me. 
First we need to add two fields to the user model. So create a module(user_restriction) in the server (openerp-server/bin/addons) in which create a model inheriting res.users as follows:

  1. 
    class users(osv.osv): 
    
  2. 
        _inherit = 'res.users' 
    
  3. 
        _name = 'res.users' 
    
  4. 
     
    
  5. 
        _columns = { 
    
  6. 
                    'session_id' : fields.char('Session Id', size=100), 
    
  7. 
                    'expiration_date' : fields.datetime('Expiration Date'), 
    
  8. 
                    } 
    

 


Some useful functions

Now we will be creating some useful functions that are to be used to do our task. 
For that create a file named user_restriction.py in the openerp-web (openerp-web/addons/openerp/controllers).

  1. 
    from openerp.utils import rpc
    
  2. 
    import cherrypy
    
  3. 
    import datetime
    
  4. 
    import pytz
    
  5. 
    DATE_FORMAT_GMT = '%a, %d %b %Y %H:%M:%S GMT'
    
  6. 
    DATE_FORMAT_ISO = '%Y-%m-%d %H:%M:%S'
    
  7. 
    MODULE_NAME = 'user_restriction'
    
  8. 
     
    
  9. 
    def _get_user_id():
    
  10. 
             return rpc.session.storage['uid']
    
  11. 
     
    
  12. 
    def _get_user_details():
    
  13. 
             return rpc.RPCProxy('res.users').read(_get_user_id())
    
  14. 
     
    
  15. 
    def update_user_session(data):
    
  16. 
        rpc.RPCProxy('res.users').write(_get_user_id(), data, rpc.session.context)
    
  17. 
     
    
  18. 
    def is_user_restriction_module_installed():
    
  19. 
                if not rpc.session.storage.get(MODULE_NAME):
    
  20. 
            user_restriction_module_ids = 
    
  21. 
                rpc.RPCProxy('ir.module.module'.search( \
    
  22. 
                            [('name', '=', MODULE_NAME), ('state', '=', 'installed')])
    
  23. 
            user_details = _get_user_details()
    
  24. 
            rpc.session.storage[MODULE_NAME] = \
    
  25. 
                           ((len(user_restriction_module_ids) == 1) \
    
  26. 
                            and ('session_id' in user_details.keys()))
    
  27. 
        return rpc.session.storage[MODULE_NAME]
    
  28. 
     
    
  29. 
    def _get_user(): 
    
  30. 
               return rpc.session.storage['user'] 
    
  31. 
     
    
  32. 
    def _get_date_string(date_obj, date_format): 
    
  33. 
        date_string = None 
    
  34. 
                if date_obj: 
    
  35. 
            date_string = date_obj.strftime(date_format)
    
  36. 
                return date_string
    
  37. 
     
    
  38. 
    def _get_date_obj(date_string, date_format):
    
  39. 
        date_obj = None
    
  40. 
                if date_string:
    
  41. 
            date_obj = datetime.datetime.strptime(date_string, date_format)
    
  42. 
                return date_obj
    
  43. 
     
    
  44. 
    def get_date_obj(date_string):
    
  45. 
                return _get_date_obj(date_string, DATE_FORMAT_GMT)
    
  46. 
     
    
  47. 
    def _get_local_time_in_gmt():
    
  48. 
        current_gmt_date = datetime.datetime.now(pytz.timezone('GMT'))
    
  49. 
        current_gmt_date_string = _get_date_string \
    
  50. 
                            (current_gmt_date, DATE_FORMAT_GMT)
    
  51. 
        current_date = _get_date_obj \
    
  52. 
                           (current_gmt_date_string, DATE_FORMAT_GMT)
    
  53. 
                 return current_date
    
  54. 
     
    
  55. 
    def has_user_loged_in(action):
    
  56. 
        restrict_login = False
    
  57. 
                if action == 'login' and is_user_restriction_module_installed():
    
  58. 
            result = _get_user_details()
    
  59. 
            previous_expiration_date_string = result['expiration_date']
    
  60. 
            previous_expiration_date = \
    
  61. 
                _get_date_obj(previous_expiration_date_string, DATE_FORMAT_ISO) 
    
  62. 
     
    
  63. 
        cookie = cherrypy.response.cookie
    
  64. 
        current_session_id = cookie['session_id'].value
    
  65. 
        current_expiration_date = _get_date_obj\
    
  66. 
                     (cookie['session_id']['expires'], DATE_FORMAT_GMT) 
    
  67. 
        current_date = _get_local_time_in_gmt()
    
  68. 
     
    
  69. 
                  if previous_expiration_date and \
    
  70. 
                 (previous_expiration_date - current_date > datetime.timedelta(0)):
    
  71. 
                            # Multiple Login.
    
  72. 
          restrict_login = True
    
  73. 
                   else:
    
  74. 
                            # Write Current Expiration Date to database. Login success. 
    
  75. 
          data = {'session_id' : current_session_id,
    
  76. 
                                'expiration_date' : str(current_expiration_date)} 
    
  77. 
          update_user_session(data)
    
  78. 
              return restrict_login
    
  79. 
     
    
  80. 
    def clear_session():
    
  81. 
              if is_user_restriction_module_installed():
    
  82. 
           result = _get_user_details()
    
  83. 
           cookie = cherrypy.response.cookie
    
  84. 
           current_session_id = cookie['session_id'].value
    
  85. 
                          if result['session_id'] and result['session_id'] == current_session_id:
    
  86. 
              data = {'session_id' : None, 'expiration_date' : None}
    
  87. 
              update_user_session(data) 
    
  88. 
         
    

 


All the functions are simple and straight forward and the names itself gives the idea about what the function does. The two important functions to consider here are the has_user_logged_in and clear_session. The has_user_logged_in function does the steps ii and iii and the clear_session function performs the step vi mentioned in the design above.

Now we need to find the right places in the web-client from where we can call our functions described above. I followed a trial and error method to find those places and got the following which I thought served for my purpose.

First task was to find what is happening when a user enters a wrong user name and/or password during login. Investigating this scenario I found the following function in openerp-web/addons/openerp/controllers/utils.py in line no. 83.

[文件utils.py从略]
 
If we look at it we can see that when the user is authorized then some data is set in the cookie. So I thought I will just validate the multiple login just above that (after line no. 165). So we can add the following code there.

  1. 
    import user_restriction
    
  2. 
    restrict_login = user_restriction.has_user_logged_in(action)
    
  3. 
    if restrict_login :
    
  4. 
        rpc.session.logout()
    
  5. 
            message = _("%s already logged in.\nEither from another place or from a 
    
  6. 
                         different browser. Log out from that session and try again."%(user))
    
  7. 
                return login(cherrypy.request.path_info, message=message, \
    
  8. 
             db=db, user=user, action=action, origArgs=get_orig_args(kw))
    

Next task is to clear the session details when the user logs out. 
By looking at the source , we can find that the logout function is defined in the class Root(openerp-web/addons/openerp/controllers/root.py line no. 162).

The original code for the function is as follows.
  1. 
    def logout(self):
    
  2. 
                  """ Logout method, will terminate the current session.
    
  3. 
          """
    
  4. 
       rpc.session.logout()
    
  5. 
                 raise redirect('/')
    

We can modify it to call our clear_session which we defined in user_restriction.py file. The modified code will be like this.
  1. 
    def logout(self):
    
  2. 
                """ Logout method, will terminate the current session.
    
  3. 
        """
    
  4. 
                import user_restriction 
    
  5. 
                if rpc.session.storage.get(user_restriction.MODULE_NAME):
    
  6. 
          rpc.session.storage.delete(user_restriction.MODULE_NAME)
    
  7. 
      user_restriction.clear_session()
    
  8. 
      rpc.session.logout()
    
  9. 
                raise redirect('/')
    

So now our major problems are solved. 

The next task is to update the expiration_date of the user session when the user is active, that is, whenever a user performs an operation. There can be a variety of operations a user can perform so finding a place to update for each operation is not a solution. So I kept looking for a central point or a base class through which all the calls will be passing through. Fortunately such a class do exist in the web-client – BaseController class (openerp-web/openobject/controllers/_base.py line no. 42). The BaseController class has only one method _get_path(). The code of the original method is as follows.

  1. 
        def _get_path(self):
    
  2. 
                return self._cp_path
    

 

We modify it as follows.

  1. 
        def _get_path(self): 
    
  2. 
                from openerp.controllers import user_restriction 
    
  3. 
                import cherrypy 
    
  4. 
                if user_restriction.is_user_restriction_module_installed(): 
    
  5. 
        cookie = cherrypy.response.cookie
    
  6. 
        data = {'session_id' : cookie['session_id'].value, 
    
  7. 
                'expiration_date' : str(user_restriction.get_date_obj(cookie['session_id']['expires']))} 
    
  8. 
          user_restriction.update_user_session(data) 
    
  9. 
                  return self._cp_path
    

With all these changes in place we can successfully stop the multiple login of a user to OpenERP.

Some Helpful Links
http://www.cherrypy.org/chrome/common/2.1/docs/book/chunk/index.html
http://www.cherrypy.org/wiki/CherryPySessions
http://tools.cherrypy.org/wiki/AuthenticationAndAccessRestrictions
http://tools.cherrypy.org/wiki/CASAuthentication


 

0

阅读 评论 收藏 转载 喜欢 打印举报/Report
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 电话:4000520066 提示音后按1键(按当地市话标准计费) 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有