在前邊的一篇文章中,我們提到了利用二次驗證增強Odoo登錄的可靠性:http://www.cnblogs.com/kfx2007/p/6023991.html
今天我們來具體實現這一步:
后端的實現
我們需要一個地方來存儲二次驗證的安全碼,拓展用戶字段:
class res_users(models.Model): _inherit='res.users' enable_google_auth = fields.Boolean(u'啟用Google兩步驗證') otp_str = fields.Char('QR Codes') google_auth_img = fields.Binary('Google Authontication QR',compute="_get_qr_img")
安全碼采用隨機字符,並用二維碼的方式呈現出來:
@api.one def btn_gen(self): base32 = pyotp.random_base32() self.otp_str = base32 @api.one def _get_qr_img(self): #check login if '@' not in self.login: raise except_orm(_('Error!'),_('Invlid Login!')) totp = pyotp.TOTP(self.otp_str) qrcodes = totp.provisioning_uri(self.login) img = qrcode.make(qrcodes) buf = StringIO.StringIO() img.save(buf,'PNG') self.google_auth_img = buf.getvalue().encode('base64')
這里需要注意的是,web頁面並不能直接將python的image展示出來,需要將其用base64 encode之后展示出來。
前端的實現
根據個人需求,前端的驗證方式可以有多種,這里以密碼+6位隨機數字的方式為例:
class google(openerp.addons.web.controllers.main.Home): @http.route('/web/login',type='http',auth='public',website=True) def web_login(self,*args,**kargs): if request.httprequest.method=='POST' and not request.params.get('qsso'): #Check Google Authentication uids = request.registry.get('res.users').search(request.cr,openerp.SUPERUSER_ID,[('login','=',request.params['login'])]) qcontext={} if not len(uids): qcontext['error'] = _("User doesn't exist! Please contact system administrator!") user = request.registry.get('res.users').browse(request.cr,openerp.SUPERUSER_ID,uids) if user.enable_google_auth and user.otp_str: totp = pyotp.TOTP(user.otp_str) otpcode = totp.now() check_code = request.params['password'][-6:] check_passwd = request.params['password'][:-6] if request.params['password'][-6:] == otpcode: request.params['password']=check_passwd return super(google,self).web_login(*args,**kargs) else: qcontext['error'] = 'Your Google Authentication Failed!' return request.render('web.login', qcontext) return super(google,self).web_login(*args,**kargs)
主要的思路是當用戶傳過來的密碼 截取后6位與生成的6位驗證碼進行驗證,如果驗證通過再去驗證前幾位的密碼字符,否則直接不允許登錄。
效果圖如下:
登錄界面失敗以后的界面: