Skip to content

Commit

Permalink
通过oauth扩展
Browse files Browse the repository at this point in the history
  • Loading branch information
ongood committed Jul 23, 2019
1 parent b41c97e commit e44e7ea
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 112 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ wheels/
*.egg-info/
.installed.cfg
*.egg
.vscode/
MANIFEST

# PyInstaller
Expand Down
6 changes: 3 additions & 3 deletions odoo_sms/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,18 @@
'author': "SuXueFeng",
'website': "https://www.sxfblog.com",
'category': 'sms',
'version': '1.0',
'depends': ['base', 'hr', 'contacts'],
'version': '1.1',
'depends': ['base', 'hr', 'contacts', 'auth_oauth'],
'installable': True,
'application': True,
'auto_install': False,
'data': [
'data/auth_oauth_data.xml',
'security/ir.model.access.csv',
'security/odoo_sms.xml',
'views/menu.xml',
'views/sms_config.xml',
'views/sms_templates.xml',
'views/res_user.xml',
'views/sms_record.xml',
]
}
135 changes: 91 additions & 44 deletions odoo_sms/controllers/sms_login.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,41 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###################################################################################
import base64
import datetime
import odoo
import json
import logging
from odoo import http, _
from odoo.addons.web.controllers.main import ensure_db, Home
from odoo.http import request
from qcloudsms_py import SmsSingleSender
import random

from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.request import CommonRequest
from qcloudsms_py import SmsSingleSender
from werkzeug.exceptions import BadRequest

from odoo import SUPERUSER_ID, _, api, http
from odoo import registry as registry_get
from odoo.addons.auth_oauth.controllers.main import OAuthLogin
from odoo.addons.web.controllers.main import (Home, ensure_db,
set_cookie_and_redirect)
from odoo.http import request

_logger = logging.getLogger(__name__)


class SMSLogin(OAuthLogin):
def list_providers(self):
"""
通过oauth打开SMS入口
:param kw:
:return:
"""
result = super(SMSLogin, self).list_providers()
for provider in result:
if 'sms' in provider['auth_endpoint']:
provider['auth_link'] = "%s%s" % (request.httprequest.url, provider['auth_endpoint'])

return result


class OdooSmsController(Home, http.Controller):

@http.route()
Expand All @@ -51,7 +70,7 @@ def web_login(self, *args, **kw):
response.qcontext['sms_config_length'] = services
return response

@http.route('/web/odoo/sms/login', type='http', auth='public', website=True, sitemap=False)
@http.route('/web/login/sms', type='http', auth='public', website=True, sitemap=False)
def web_odoo_sms_login(self, *args, **kw):
"""
短信登录入口,点击后返回到验证码界面
Expand All @@ -76,7 +95,7 @@ def web_send_sms_code_by_phone(self, **kw):
"""
user_phone = request.params['user_phone']
# 验证是否存在系统用户
users = request.env['res.users'].sudo().search([('login_phone', '=', user_phone)])
users = request.env['res.users'].sudo().search([('oauth_uid', '=', user_phone)])
if not users:
return json.dumps({'state': False, 'msg': "该手机号码未绑定系统用户,请注册!"})
# 判断要使用的短信平台,获取配置中已开启的短信平台服务
Expand Down Expand Up @@ -179,7 +198,7 @@ def create_record(self, user_phone, service, sms_sid, code, timeout):
:param timeout: 超时时长
:return:
"""
users = request.env['res.users'].sudo().search([('login_phone', '=', user_phone)])
users = request.env['res.users'].sudo().search([('oauth_uid', '=', user_phone)])
record = request.env['sms.verification.record'].sudo().create({
'service_id': service.id,
'user_id': users[0].id if users else False,
Expand Down Expand Up @@ -212,47 +231,75 @@ def check_verification_code(self, **kw):
records.sudo().write({'state': 'invalid'})
return self._web_post_login(phone)

# def _web_post_login(self, phone):
# """
# 登录跳转
# :param phone:
# :param redirect:
# :return:
# """
# ensure_db()
# redirect = None
# request.params['login_success'] = False
# if request.httprequest.method == 'GET' and redirect and request.session.uid:
# return http.redirect_with_hash(redirect)
# if not request.uid:
# request.uid = odoo.SUPERUSER_ID
# values = request.params.copy()
# try:
# values['databases'] = http.db_list()
# except odoo.exceptions.AccessDenied:
# values['databases'] = None
# # 验证是否存在系统用户
# user = request.env['res.users'].sudo().search([('login_phone', '=', phone)], limit=1)
# if not user:
# return json.dumps({'state': False, 'msg': "该手机号码未绑定系统用户,请维护!"})
# login = user.login
# if user.odoo_sms_token:
# password = base64.b64decode(user.odoo_sms_token).decode(encoding='utf-8', errors='strict')
# else:
# try:
# user.sudo().write({'password': login})
# password = login
# except Exception as e:
# return json.dumps({'state': False, 'msg': "登录失败,具体原因为;{}".format(str(e))})
# try:
# uid = request.session.authenticate(request.session.db, login, password)
# if uid is not False:
# request.params['login_success'] = True
# return json.dumps({'state': True, 'msg': "登录成功"})
# else:
# return json.dumps({'state': False, 'msg': "登录失败,请稍后重试!"})
# except Exception as e:
# return json.dumps({'state': False, 'msg': "登录失败!原因为:{}".format(str(e))})

def _web_post_login(self, phone):
"""
登录跳转
验证手机并登陆系统
:param phone:
:param redirect:
:return:
"""
ensure_db()
redirect = None
request.params['login_success'] = False
if request.httprequest.method == 'GET' and redirect and request.session.uid:
return http.redirect_with_hash(redirect)
if not request.uid:
request.uid = odoo.SUPERUSER_ID
values = request.params.copy()
try:
values['databases'] = http.db_list()
except odoo.exceptions.AccessDenied:
values['databases'] = None
# 验证是否存在系统用户
user = request.env['res.users'].sudo().search([('login_phone', '=', phone)], limit=1)
if not user:
return json.dumps({'state': False, 'msg': "该手机号码未绑定系统用户,请维护!"})
login = user.login
if user.odoo_sms_token:
password = base64.b64decode(user.odoo_sms_token).decode(encoding='utf-8', errors='strict')
else:
dbname = request.session.db
if not http.db_filter([dbname]):
return BadRequest()
provider = 'sms'
context = {}
registry = registry_get(dbname)
with registry.cursor() as cr:
try:
user.sudo().write({'password': login})
password = login
env = api.Environment(cr, SUPERUSER_ID, context)
credentials = env['res.users'].sudo().auth_oauth_sms(provider, phone)
cr.commit()
url = '/web'
uid = request.session.authenticate(*credentials)
if uid is not False:
request.params['login_success'] = True
return json.dumps({'state': True, 'msg': "登录成功"})
except Exception as e:
return json.dumps({'state': False, 'msg': "登录失败,具体原因为;{}".format(str(e))})
try:
uid = request.session.authenticate(request.session.db, login, password)
if uid is not False:
request.params['login_success'] = True
return json.dumps({'state': True, 'msg': "登录成功"})
else:
return json.dumps({'state': False, 'msg': "登录失败,请稍后重试!"})
except Exception as e:
return json.dumps({'state': False, 'msg': "登录失败!原因为:{}".format(str(e))})
# signup error
_logger.exception("OAuth2: %s" % str(e))
url = "/web/login?oauth_error=2"
return set_cookie_and_redirect(url)

def _get_config_template(self, service, tem_type):
"""
Expand Down Expand Up @@ -282,4 +329,4 @@ def generate_random_numbers(self, length_size):
for i in range(length_size):
ch = chr(random.randrange(ord('0'), ord('9') + 1))
numbers += ch
return numbers
return numbers
13 changes: 13 additions & 0 deletions odoo_sms/data/auth_oauth_data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="provider_sms" model="auth.oauth.provider">
<field name="name">手机动态验证码登陆</field>
<field name="auth_endpoint">/sms</field>
<field name="validation_endpoint">/sms</field>
<field name="css_class">fa fa-fw fa-mobile</field>
<field name="body">手机动态验证码登陆</field>
<field name="enabled" eval="True"/>
</record>
</data>
</odoo>
58 changes: 38 additions & 20 deletions odoo_sms/models/res_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,40 +25,58 @@
from qcloudsms_py import SmsSingleSender
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.request import CommonRequest
from odoo.exceptions import AccessDenied

_logger = logging.getLogger(__name__)


class ResUsers(models.Model):
_inherit = 'res.users'

login_phone = fields.Char(string='手机号码', help="用于使用手机验证码登录系统", copy=False)
odoo_sms_token = fields.Char(string='SmsToken')

@api.constrains('login_phone')
@api.constrains('oauth_uid')
def constrains_login_phone(self):
"""
检查手机号码是否被占用
检查手机是否重复
:return:
"""
for res in self:
if res.login_phone:
users = self.env['res.users'].sudo().search([('login_phone', '=', res.login_phone)])
if res.oauth_uid:
users = self.env['res.users'].sudo().search([('oauth_uid', '=', res.oauth_uid)])
if len(users) > 1:
raise UserError("抱歉!{}手机号码已被'{}'占用,请解除或更换号码!".format(res.login_phone, users[0].name))
raise UserError("抱歉!{}手机号码(令牌)已被'{}'占用,请解除或更换号码!".format(res.oauth_uid, users[0].name))

def _set_password(self):
"""
修改密码后,短信通知到用户
:return:
"""
for user in self:
user.sudo().write({'odoo_sms_token': base64.b64encode(user.password.encode('utf-8'))})
if user.login_phone:
result = self.send_change_password_sms(user.login, user.password, user.login_phone)
if not result['state']:
raise ValidationError("抱歉,系统发送修改密码通知短信不成功,请检查原因;Error:{}".format(result['msg']))
super(ResUsers, self)._set_password()
@api.model
def auth_oauth_sms(self, provide_id, oauth_uid):
if provide_id == 'sms':
user_ids = self.search([('oauth_uid', '=', oauth_uid)])
else:
user_ids = self.search([('oauth_provider_id', '=', provide_id), ('oauth_uid', '=', oauth_uid)])
_logger.info("user: %s", user_ids)
if not user_ids or len(user_ids) > 1:
raise AccessDenied()
return (self.env.cr.dbname, user_ids[0].login, oauth_uid)

@api.model
def _check_credentials(self, password):
try:
return super(ResUsers, self)._check_credentials(password)
except AccessDenied:
res = self.sudo().search([('id', '=', self.env.uid), ('oauth_uid', '=', password)])
if not res:
raise

# def _set_password(self):
# """
# 修改密码后,短信通知到用户
# :return:
# """
# for user in self:
# user.sudo().write({'odoo_sms_token': base64.b64encode(user.password.encode('utf-8'))})
# if user.login_phone:
# result = self.send_change_password_sms(user.login, user.password, user.login_phone)
# if not result['state']:
# raise ValidationError("抱歉,系统发送修改密码通知短信不成功,请检查原因;Error:{}".format(result['msg']))
# super(ResUsers, self)._set_password()

def send_change_password_sms(self, login, password, phone):
"""
Expand Down
28 changes: 0 additions & 28 deletions odoo_sms/views/res_user.xml

This file was deleted.

17 changes: 0 additions & 17 deletions odoo_sms/views/sms_templates.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,6 @@
</xpath>
</template>

<template id="odoo_sms.odoo_sms_login" name="OAuth Odoo SMS">
<t t-if="sms_config_length &gt; 0">
<em t-attf-class="d-block text-center text-muted small}">- 或者 -</em>
<div class="o_auth_oauth_providers list-group mt-1 mb-1 text-left">
<a t-attf-href="/web/odoo/sms/login" class="list-group-item list-group-item-action py-2" >
<i class="fa fa-mobile"/>&#160;&#160;<t>手机动态验证码登录</t>
</a>
</div>
</t>
</template>

<template id="odoo_sms.login" inherit_id="web.login" name="Phone SMS Login">
<xpath expr="//div[hasclass('o_login_auth')]" position="inside">
<t t-call="odoo_sms.odoo_sms_login"/>
</xpath>
</template>

<template id="odoo_sms.login_signup" name="Odoo Sms Login">
<t t-call="web.login_layout">
<form class="oe_signup_form" role="form" method="post" t-if="not message">
Expand Down

0 comments on commit e44e7ea

Please sign in to comment.