在前边的一篇文章中,我们提到了利用二次验证增强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位验证码进行验证,如果验证通过再去验证前几位的密码字符,否则直接不允许登录。
效果图如下:
登录界面失败以后的界面: