功能介绍

对用户表扩展手机号码字段,允许用户通过手机号码与验证码的方式进行认证,注册,重置密码以及更换手机号。
多因素身份认证 (MFA) 是保护企业 IT 资源访问安全的一种关键工具,也是零信任安全模型的核心组成。特别在远程办公以及数据泄露事件层出不穷的背景下,越来越多企业都开始考虑实施多因素身份认证策略。
根据近期一项对 IT 专业人员的调查,52.6%的中小型企业已经要求为所有应用程序和系统登录添加多因素身份认证。其中手机推送认证形式(无密码认证)的二次认证是保证良好用户体验的绝佳选择。
开源IDaaS方舟一账通ArkID系统内置手机验证码认证插件简单配置、马上可用,降低实施成本,提升应用集成效率。

普通用户:

在 “注册” 页面实现手机号码+验证码用户注册
在 “登录” 页面实现手机号码+验证码用户登录
在 “更改密码” 页面实现手机号码+验证码方式下密码更改
在 “我的 - 认证管理“ 中添加重置手机号码的功能

租户管理员

在”用户管理 - 用户列表“中编辑页面添加手机号码编辑功能

前置条件

需配合短信插件使用,系统已默认提供阿里云短信插件,如需查看配置方法请移步阿里云短信插件文档。

配置指南

01 插件租赁
经由左侧菜单栏依次进入【租户管理】->【插件管理】,在插件租赁页面中找到手机验证码认证因素插件卡片,点击租赁

02 认证因素配置

** 03 登录界面**

** 04 注册界面**

** 05 密码修改界面**

** 06 更换手机号码界面**

由用户头像菜单进入【认证管理】界面,选择更改手机号码标签页

实现思路#
普通用户:手机号码+验证码用户注册/登录/重置密码:

普通用户:重置手机号码:

管理员用户: 更换用户手机号码

抽象方法实现

  • load
  • authenticate
  • register
  • reset_password
  • create_login_page
  • create_register_page
  • create_password_page
  • create_other_page
  • create_auth_manage_page
  • check_auth_data
  • f - ix_login_page

代码

extension_root.com_longgui_auth_factor_mobile.MobileAuthFactorExtension (AuthFactorExtension)

手机短信验证码认证因素插件

Source code in
extension_root/com_longgui_auth_factor_mobile/init.py

class MobileAuthFactorExtension(AuthFactorExtension):"""手机短信验证码认证因素插件"""def load(self):"""加载插件"""super().load()self.create_extension_config_schema()self.register_extend_field(UserMobile, "mobile")from api.v1.schema.auth import AuthInfrom api.v1.schema.user import UserCreateIn,UserItemOut,UserUpdateIn,UserListItemOutfrom api.v1.schema.mine import ProfileSchemaOutself.register_extend_api(AuthIn,UserCreateIn, UserItemOut, UserUpdateIn, UserListItemOut,mobile=(Optional[str],Field(title=_("电话号码"))),# areacode=(str,Field(title=_("区号"))))self.register_extend_api(ProfileSchemaOut, mobile=(Optional[str],Field(readonly=True)))# 注册发送短信接口self.url_send_sms_code = self.register_api('/config/{config_id}/send_sms_code/','POST',self.send_sms_code,tenant_path=True,auth=None,response=SendSMSCodeOut,)print(self.url_send_sms_code)def authenticate(self, event, **kwargs):""" 认证通过手机号码查找用户并校验短信验证码Args:event (Event): 事件"""tenant = event.tenantrequest = event.requestdata = request.POST or json.load(request.body)mobile = data.get('mobile')sms_code = data.get('sms_code')user = User.expand_objects.filter(tenant=tenant,mobile=mobile)if len(user) > 1:logger.error(f'{mobile}在数据库中匹配到多个用户')return self.auth_failed(event, data=self.error(ErrorCode.CONTACT_MANAGER))if user:user = user[0]if check_sms_code(mobile, sms_code):user = User.active_objects.get(id=user.get("id"))return self.auth_success(user,event)else:msg = ErrorCode.SMS_CODE_MISMATCHelse:msg = ErrorCode.MOBILE_NOT_EXISTS_ERRORreturn self.auth_failed(event, data=self.error(msg))@transaction.atomic()def register(self, event, **kwargs):""" 注册用户Args:event (Event): 事件"""tenant = event.tenantrequest = event.requestdata = request.POST or json.load(request.body)mobile = data.get('mobile')sms_code = data.get('sms_code')username = data.get('username')config = self.get_current_config(event)ret, message = self.check_mobile_exists(mobile, tenant)if not ret:return self.error(message)if not check_sms_code(mobile, sms_code):return self.error(ErrorCode.SMS_CODE_MISMATCH)ret, message = self.check_username_exists(username, tenant)if not ret:return self.error(message)user = User(tenant=tenant)user.mobile = mobileuser.username = usernameuser.save()tenant.users.add(user)tenant.save()return userdef reset_password(self, event, **kwargs):""" 重置密码Args:event (Event): 事件"""tenant = event.tenantrequest = event.requestdata = request.POST or json.load(request.body)mobile = data.get('mobile')sms_code = data.get('sms_code')password = data.get('password')checkpassword = data.get('checkpassword')if password != checkpassword:return self.error(ErrorCode.PASSWORD_IS_INCONSISTENT)if not check_sms_code(mobile, sms_code):return self.error(ErrorCode.SMS_CODE_MISMATCH)user = User.expand_objects.filter(tenant=tenant,mobile=mobile)if len(user) > 1:logger.error(f'{mobile}在数据库中匹配到多个用户')return self.error(ErrorCode.CONTACT_MANAGER)if user:user = user[0]user = User.active_objects.get(id=user.get("id"))user.password = make_password(password)user.save()return self.success()return self.error(ErrorCode.MOBILE_NOT_EXISTS_ERROR)def create_login_page(self, event, config, config_data):""" 生成手机验证码登录页面Schema描述Args:event (Event): 事件config (TenantExtensionConfig): 插件运行时配置"""items = [{"type": "text","name":"mobile","placeholder": "手机号码","append": {"title": "发送验证码","http": {"url": self.url_send_sms_code,"method": "post","params": {"mobile": "mobile","areacode": "86",},},"delay": 60}},{"type": "text","name":"sms_code","placeholder": "验证码",}]self.add_page_form(config, self.LOGIN, "手机验证码登录", items, config_data)def create_register_page(self, event, config, config_data):"""生成手机验证码用户注册页面Schema描述因本插件提供重置密码功能,此处需用户指定账号用户名Args:event (Event): 事件config (TenantExtensionConfig): 插件运行时配置"""items = [{"type": "text","name": "username","placeholder": "用户名"},{"type": "text","name":"mobile","placeholder": "手机号码","append": {"title": "发送验证码","http": {"url": self.url_send_sms_code,"method": "post","params": {"mobile": "mobile","areacode": "86",},},"delay": 60}},{"type": "text","name":"sms_code","placeholder": "验证码"}]self.add_page_form(config, self.REGISTER, "手机验证码注册", items, config_data)def create_password_page(self, event, config, config_data):"""生成重置密码页面Schema描述通过手机验证码重置密码时需提供手机号码以及对应验证码,同时此处添加新密码确认机制注意:重置密码功能需要启用用户名密码认证插件以提供完整支持Args:event (Event): 事件config (TenantExtensionConfig): 插件运行时配置"""items = [{"type": "text","name":"mobile","placeholder": "手机号码","append": {"title": "发送验证码","http": {"url": self.url_send_sms_code,"method": "post","params": {"mobile": "mobile","areacode": "86",},},}},{"type": "text","name":"sms_code","placeholder": "验证码"},{"type": "password","name":"password","placeholder": "密码"},{"type": "password","name":"checkpassword","placeholder": "密码确认"}]self.add_page_form(config, self.RESET_PASSWORD, "手机验证码重置密码", items, config_data)def create_other_page(self, event, config, config_data):"""创建其他页面(本插件无相关页面)Args:event (Event): 事件config (TenantExtensionConfig): 插件运行时配置"""passdef check_mobile_exists(self, mobile, tenant):"""检查电话号码是否已存在Args:mobile (str): 手机号tenant (Tenant): 租户Returns:(bool,ErrorCode): mobile是否存在以及对应错误"""if not mobile:return False, ErrorCode.MOBILE_EMPTYif User.expand_objects.filter(tenant=tenant,mobile=mobile).count():return False, ErrorCode.MOBILE_EXISTS_ERRORreturn True, Nonedef check_username_exists(self,username,tenant):"""检查用户名是否已存在Args:username (str): 用户名tenant (Tenant): 租户Returns:(bool,ErrorCode): username是否存在以及对应错误"""# 检查username是否为空if not username:return False, ErrorCode.USERNAME_EMPTY# 检查username是否已存在if User.expand_objects.filter(tenant=tenant,username=username).count():return False, ErrorCode.USERNAME_EXISTS_ERRORreturn True, Nonedef check_auth_data(self, event, **kwargs):passdef fix_login_page(self, event, **kwargs):passdef create_auth_manage_page(self):""" 创建“我的-认证管理”中的更换手机号码页面"""_pages = []mine_mobile_path = self.register_api("/mine_mobile/","GET",self.mine_mobile,tenant_path=True,auth=GlobalAuth(),response=MineMobileOut)upodate_mine_mobile_path = self.register_api("/mine_mobile/",'POST',self.update_mine_mobile,tenant_path=True,auth=GlobalAuth(),response=UpdateMineMobileOut)name = '更改手机号码'page = pages.FormPage(name=name)page.create_actions(init_action=actions.DirectAction(path=mine_mobile_path,method=actions.FrontActionMethod.GET,),global_actions={'confirm': actions.ConfirmAction(path=upodate_mine_mobile_path),})_pages.append(page)return _pagesdef create_extension_config_schema(self):"""创建插件运行时配置schema描述"""select_sms_page = pages.TablePage(select=True,name=_("指定短信插件运行时"))self.register_front_pages(select_sms_page)select_sms_page.create_actions(init_action=actions.DirectAction(path='/api/v1/tenants/{tenant_id}/config_select/?extension__type=sms',method=actions.FrontActionMethod.GET))MobileAuthFactorSchema = create_extension_schema('MobileAuthFactorSchema',__file__, [('sms_config', MobileAuthFactorConfigSchema, Field(title=_('sms extension config', '短信插件运行时'),page=select_sms_page.tag,),),('code_length', int, Field(title=_('code_length', '验证码长度'),default=6)),('expired', Optional[int],Field(title=_('expired', '有效期/分钟'),default=10,)),],BaseAuthFactorSchema,)self.register_auth_factor_schema(MobileAuthFactorSchema, 'mobile')@operation(SendSMSCodeOut)def send_sms_code(self,request,tenant_id,config_id:str,data:SendSMSCodeIn):"""发送短信验证码"""tenant = request.tenantmobile = data.mobileconfig = self.get_config_by_id(config_id)if not config:return self.error(ErrorCode.CONFIG_IS_NOT_EXISTS)if not mobile or mobile=="mobile":return self.error(ErrorCode.MOBILE_EMPTY)code = create_sms_code(tenant,mobile,config.config.get('code_length',6),config.config.get("expired",10)*60)responses = dispatch_event(Event(tag=SEND_SMS,tenant=tenant,request=request,data={"config_id":config.config["sms_config"]["id"],"mobile":data.mobile,"code": code,"areacode": data.areacode,"username": request.user.username if request.user else ""},packages=config.config["sms_config"]["package"]))if not responses:return self.error(ErrorCode.SMS_EXTENSION_NOT_EXISTS)useless, (data, extension) = responses[0]if data:return self.success()else:return self.error(ErrorCode.SMS_SEND_FAILED)@operation(UpdateMineMobileOut,roles=[TENANT_ADMIN, PLATFORM_ADMIN, NORMAL_USER])def update_mine_mobile(self, request, tenant_id: str,data:UpdateMineMobileIn):""" 普通用户:更新手机号码"""mobile = data.mobileret, message = self.check_mobile_exists(mobile, request.tenant)if not ret:return self.error(message)if not check_sms_code(request.tenant,mobile,data.code):return self.error(ErrorCode.SMS_CODE_MISMATCH)user = request.useruser.mobile=data.mobileuser.save()return self.success()@operation(MineMobileOut,roles=[TENANT_ADMIN, PLATFORM_ADMIN, NORMAL_USER])def mine_mobile(self,request,tenant_id: str):user = request.useruser_expand = User.expand_objects.filter(id=user.id).first()config = self.get_tenant_configs(request.tenant).first()if not config:return self.error(ErrorCode.CONFIG_IS_NOT_EXISTS)return self.success(data={"current_mobile": user_expand.get("mobile",None),"mobile": "","code": "","config_id": config.id.hex,},)

authenticate(self, event, **kwargs)
认证
通过手机号码查找用户并校验短信验证码
Parameters:

Name Type Description Default
event Event 事件 required

Source code in
extension_root/com_longgui_auth_factor_mobile/init.py

def authenticate(self, event, **kwargs):""" 认证通过手机号码查找用户并校验短信验证码Args:event (Event): 事件"""tenant = event.tenantrequest = event.requestdata = request.POST or json.load(request.body)mobile = data.get('mobile')sms_code = data.get('sms_code')user = User.expand_objects.filter(tenant=tenant,mobile=mobile)if len(user) > 1:logger.error(f'{mobile}在数据库中匹配到多个用户')return self.auth_failed(event, data=self.error(ErrorCode.CONTACT_MANAGER))if user:user = user[0]if check_sms_code(mobile, sms_code):user = User.active_objects.get(id=user.get("id"))return self.auth_success(user,event)else:msg = ErrorCode.SMS_CODE_MISMATCHelse:msg = ErrorCode.MOBILE_NOT_EXISTS_ERRORreturn self.auth_failed(event, data=self.error(msg))

check_auth_data(self, event, **kwargs)
响应检查认证凭证事件
Parameters:

Name Type Description Default
event AUTHRULE_CHECK_AUTH_DATA事件 required

Source code in
extension_root/com_longgui_auth_factor_mobile/init.py

def check_auth_data(self, event, **kwargs):pass

check_mobile_exists(self, mobile, tenant)
检查电话号码是否已存在
Parameters:

Name Type Description Default
mobile str 手机号 required
tenant Tenant 租户 required

Returns:

Type Description
(bool,ErrorCode) mobile是否存在以及对应错误

Source code in
extension_root/com_longgui_auth_factor_mobile/init.py

def check_mobile_exists(self, mobile, tenant):"""检查电话号码是否已存在Args:mobile (str): 手机号tenant (Tenant): 租户Returns:(bool,ErrorCode): mobile是否存在以及对应错误"""if not mobile:return False, ErrorCode.MOBILE_EMPTYif User.expand_objects.filter(tenant=tenant,mobile=mobile).count():return False, ErrorCode.MOBILE_EXISTS_ERRORreturn True, None

check_username_exists(self, username, tenant) #
检查用户名是否已存在
Parameters:

Name Type Description Default
username str 用户名 required
tenant Tenant 租户 required

Returns:

Type Description
(bool,ErrorCode) username是否存在以及对应错误

Source code in
extension_root/com_longgui_auth_factor_mobile/init.py

def check_username_exists(self,username,tenant):"""检查用户名是否已存在Args:username (str): 用户名tenant (Tenant): 租户Returns:(bool,ErrorCode): username是否存在以及对应错误"""# 检查username是否为空if not username:return False, ErrorCode.USERNAME_EMPTY# 检查username是否已存在if User.expand_objects.filter(tenant=tenant,username=username).count():return False, ErrorCode.USERNAME_EXISTS_ERRORreturn True, None

create_auth_manage_page(self)
创建“我的-认证管理”中的更换手机号码页面

Source code in
extension_root/com_longgui_auth_factor_mobile/init.py

def create_auth_manage_page(self):""" 创建“我的-认证管理”中的更换手机号码页面"""_pages = []mine_mobile_path = self.register_api("/mine_mobile/","GET",self.mine_mobile,tenant_path=True,auth=GlobalAuth(),response=MineMobileOut)upodate_mine_mobile_path = self.register_api("/mine_mobile/",'POST',self.update_mine_mobile,tenant_path=True,auth=GlobalAuth(),response=UpdateMineMobileOut)name = '更改手机号码'page = pages.FormPage(name=name)page.create_actions(init_action=actions.DirectAction(path=mine_mobile_path,method=actions.FrontActionMethod.GET,),global_actions={'confirm': actions.ConfirmAction(path=upodate_mine_mobile_path),})_pages.append(page)return _pages

create_extension_config_schema(self)
创建插件运行时配置schema描述

Source code in
extension_root/com_longgui_auth_factor_mobile/init.py

create_login_page(self, event, config, config_data)
生成手机验证码登录页面Schema描述

Parameters:

Name Type Description Default
event Event 事件 required
config TenantExtensionConfig 插件运行时配置 required

Source code in extension_root/com_longgui_auth_factor_mobile/init.py

def create_login_page(self, event, config, config_data):""" 生成手机验证码登录页面Schema描述Args:event (Event): 事件config (TenantExtensionConfig): 插件运行时配置"""items = [{"type": "text","name":"mobile","placeholder": "手机号码","append": {"title": "发送验证码","http": {"url": self.url_send_sms_code,"method": "post","params": {"mobile": "mobile","areacode": "86",},},"delay": 60}},{"type": "text","name":"sms_code","placeholder": "验证码",}]self.add_page_form(config, self.LOGIN, "手机验证码登录", items, config_data)

create_other_page(self, event, config, config_data)
创建其他页面(本插件无相关页面)
Parameters:

Name Type Description Default
event Event 事件 required
config TenantExtensionConfig 插件运行时配置 required

Source code in
extension_root/com_longgui_auth_factor_mobile/init.py

def create_other_page(self, event, config, config_data):"""创建其他页面(本插件无相关页面)Args:event (Event): 事件config (TenantExtensionConfig): 插件运行时配置"""pass

create_password_page(self, event, config, config_data) #
生成重置密码页面Schema描述

通过手机验证码重置密码时需提供手机号码以及对应验证码,同时此处添加新密码确认机制

注意:重置密码功能需要启用用户名密码认证插件以提供完整支持

Parameters:

Name Type Description Default
event Event 事件 required
config TenantExtensionConfig 插件运行时配置 required

Source code in
extension_root/com_longgui_auth_factor_mobile/init.py

def create_password_page(self, event, config, config_data):"""生成重置密码页面Schema描述通过手机验证码重置密码时需提供手机号码以及对应验证码,同时此处添加新密码确认机制注意:重置密码功能需要启用用户名密码认证插件以提供完整支持Args:event (Event): 事件config (TenantExtensionConfig): 插件运行时配置"""items = [{"type": "text","name":"mobile","placeholder": "手机号码","append": {"title": "发送验证码","http": {"url": self.url_send_sms_code,"method": "post","params": {"mobile": "mobile","areacode": "86",},},}},{"type": "text","name":"sms_code","placeholder": "验证码"},{"type": "password","name":"password","placeholder": "密码"},{"type": "password","name":"checkpassword","placeholder": "密码确认"}]self.add_page_form(config, self.RESET_PASSWORD, "手机验证码重置密码", items, config_data)

create_register_page(self, event, config, config_data)
生成手机验证码用户注册页面Schema描述
因本插件提供重置密码功能,此处需用户指定账号用户名
Parameters:

Name Type Description Default
event Event 事件 required
config TenantExtensionConfig 插件运行时配置 required

Source code in
extension_root/com_longgui_auth_factor_mobile/init.py

def create_register_page(self, event, config, config_data):"""生成手机验证码用户注册页面Schema描述因本插件提供重置密码功能,此处需用户指定账号用户名Args:event (Event): 事件config (TenantExtensionConfig): 插件运行时配置"""items = [{"type": "text","name": "username","placeholder": "用户名"},{"type": "text","name":"mobile","placeholder": "手机号码","append": {"title": "发送验证码","http": {"url": self.url_send_sms_code,"method": "post","params": {"mobile": "mobile","areacode": "86",},},"delay": 60}},{"type": "text","name":"sms_code","placeholder": "验证码"}]self.add_page_form(config, self.REGISTER, "手机验证码注册", items, config_data)

fix_login_page(self, event, **kwargs)
向login_pages填入认证元素
Parameters:

Name Type Description Default
event AUTHRULE_FIX_LOGIN_PAGE事件 required

Source code in
extension_root/com_longgui_auth_factor_mobile/init.py

def fix_login_page(self, event, **kwargs):pass

load(self)
加载插件

Source code in
extension_root/com_longgui_auth_factor_mobile/init.py

def load(self):"""加载插件"""super().load()self.create_extension_config_schema()self.register_extend_field(UserMobile, "mobile")from api.v1.schema.auth import AuthInfrom api.v1.schema.user import UserCreateIn,UserItemOut,UserUpdateIn,UserListItemOutfrom api.v1.schema.mine import ProfileSchemaOutself.register_extend_api(AuthIn,UserCreateIn, UserItemOut, UserUpdateIn, UserListItemOut,mobile=(Optional[str],Field(title=_("电话号码"))),# areacode=(str,Field(title=_("区号"))))self.register_extend_api(ProfileSchemaOut, mobile=(Optional[str],Field(readonly=True)))# 注册发送短信接口self.url_send_sms_code = self.register_api('/config/{config_id}/send_sms_code/','POST',self.send_sms_code,tenant_path=True,auth=None,response=SendSMSCodeOut,)print(self.url_send_sms_code)

register(self, event, **kwargs)
注册用户
Parameters:

Name Type Description Default
event Event 事件 required

Source code in
extension_root/com_longgui_auth_factor_mobile/init.py

@transaction.atomic()
def register(self, event, **kwargs):""" 注册用户Args:event (Event): 事件"""tenant = event.tenantrequest = event.requestdata = request.POST or json.load(request.body)mobile = data.get('mobile')sms_code = data.get('sms_code')username = data.get('username')config = self.get_current_config(event)ret, message = self.check_mobile_exists(mobile, tenant)if not ret:return self.error(message)if not check_sms_code(mobile, sms_code):return self.error(ErrorCode.SMS_CODE_MISMATCH)ret, message = self.check_username_exists(username, tenant)if not ret:return self.error(message)user = User(tenant=tenant)user.mobile = mobileuser.username = usernameuser.save()tenant.users.add(user)tenant.save()return user

reset_password(self, event, **kwargs)
重置密码

Parameters:

Name Type Description Default
event Event 事件 required

Source code in
extension_root/com_longgui_auth_factor_mobile/init.py

def reset_password(self, event, **kwargs):""" 重置密码Args:event (Event): 事件"""tenant = event.tenantrequest = event.requestdata = request.POST or json.load(request.body)mobile = data.get('mobile')sms_code = data.get('sms_code')password = data.get('password')checkpassword = data.get('checkpassword')if password != checkpassword:return self.error(ErrorCode.PASSWORD_IS_INCONSISTENT)if not check_sms_code(mobile, sms_code):return self.error(ErrorCode.SMS_CODE_MISMATCH)user = User.expand_objects.filter(tenant=tenant,mobile=mobile)if len(user) > 1:logger.error(f'{mobile}在数据库中匹配到多个用户')return self.error(ErrorCode.CONTACT_MANAGER)if user:user = user[0]user = User.active_objects.get(id=user.get("id"))user.password = make_password(password)user.save()return self.success()return self.error(ErrorCode.MOBILE_NOT_EXISTS_ERROR)

send_sms_code(self, request, tenant_id, config_id, data)
发送短信验证码

Source code in
extension_root/com_longgui_auth_factor_mobile/init.py

@operation(SendSMSCodeOut)
def send_sms_code(self,request,tenant_id,config_id:str,data:SendSMSCodeIn):"""发送短信验证码"""tenant = request.tenantmobile = data.mobileconfig = self.get_config_by_id(config_id)if not config:return self.error(ErrorCode.CONFIG_IS_NOT_EXISTS)if not mobile or mobile=="mobile":return self.error(ErrorCode.MOBILE_EMPTY)code = create_sms_code(tenant,mobile,config.config.get('code_length',6),config.config.get("expired",10)*60)responses = dispatch_event(Event(tag=SEND_SMS,tenant=tenant,request=request,data={"config_id":config.config["sms_config"]["id"],"mobile":data.mobile,"code": code,"areacode": data.areacode,"username": request.user.username if request.user else ""},packages=config.config["sms_config"]["package"]))if not responses:return self.error(ErrorCode.SMS_EXTENSION_NOT_EXISTS)useless, (data, extension) = responses[0]if data:return self.success()else:return self.error(ErrorCode.SMS_SEND_FAILED)

update_mine_mobile(self, request, tenant_id, data)
普通用户:更新手机号码

Source code in
extension_root/com_longgui_auth_factor_mobile/init.py

@operation(UpdateMineMobileOut,roles=[TENANT_ADMIN, PLATFORM_ADMIN, NORMAL_USER])
def update_mine_mobile(self, request, tenant_id: str,data:UpdateMineMobileIn):""" 普通用户:更新手机号码"""mobile = data.mobileret, message = self.check_mobile_exists(mobile, request.tenant)if not ret:return self.error(message)if not check_sms_code(request.tenant,mobile,data.code):return self.error(ErrorCode.SMS_CODE_MISMATCH)user = request.useruser.mobile=data.mobileuser.save()return self.success()

extension_root.com_longgui_auth_factor_mobile.sms
check_sms_code(tenant, mobile, code)

验证短信验证码

Source code in extension_root/com_longgui_auth_factor_mobile/sms.py

def check_sms_code(tenant,mobile, code):""" 验证短信验证码"""c_code = cache.get(tenant,gen_sms_code_key(mobile))return c_code == code

create_sms_code(tenant, phone_number, uth_code_length=6, expired=None)
生成短信验证码并存储至缓存

Source code in extension_root/com_longgui_auth_factor_mobile/sms.py

gen_sms_code_key(mobile)
生成短信验证码的key

Source code in extension_root/com_longgui_auth_factor_mobile/sms.py

def gen_sms_code_key(mobile):'''生成短信验证码的key'''return f'sms:{mobile}'

ArkID方舟一账通

一款插件化、多租户、云原生的开源统一身份认证授权管理解决方案/身份云管理平台,采用AGPL-3.0 开源协议;支持多种标准协议(LDAP, OAuth2, SAML, OpenID),细粒度权限控制,完整的WEB管理功能,钉钉、企业微信集成等。ArkID 既可以作为企业终端客户资产统一管理 CIAM,可作为企业内部雇员、外部伙伴统一身份管理平台 EIAM;助企业构建标准化的用户身份体系。如果希望快速的了解系统的基本使用,可以访问官方IDaaS注册账号后创建自己的租户,即可使用系统的大部分功能。如果希望体验超级管理员,安装配置插件等,推荐使用私有化部署的方式。

多因素身份认证 (MFA) 插件:手机验证码认证因素配置流程相关推荐

  1. 如何在Raspberry Pi上设置两因素身份验证

    Kiklas/ShutterstockKiklas /快门 The Raspberry Pi is everywhere now, which is why it's caught the eye o ...

  2. 无密码多重身份验证(MFA)2022年全球行业分析报告

    本文研究全球市场.主要地区和主要国家无密码多重身份验证(MFA)的销量.销售收入等,同时也重点分析全球范围内主要厂商(品牌)竞争态势,无密码多重身份验证(MFA)销量.价格.收入和市场份额等.   针 ...

  3. laravel集成谷歌验证_如何将Google的两因素身份验证添加到Laravel

    laravel集成谷歌验证 Laravel is a wonderful PHP framework that makes building applications with PHP a lot o ...

  4. 手机验证码常见漏洞总结

    目录 0X00 前言 0X01 无效验证 0X02 客户端验证绕过 0X03 短信轰炸 0X04 验证码爆破 0X05 验证码与手机号未绑定 0X06 代码层逻辑缺陷 0X00 前言 手机验证码在we ...

  5. 多因素身份认证之手机推送认证

    多因素身份认证 (MFA) 是保护企业 IT 资源访问安全的一种关键工具,也是零信任安全模型的核心组成.特别在远程办公以及数据泄露事件层出不穷的背景下,越来越多企业都开始考虑实施多因素身份认证策略. ...

  6. IDaaS 系统 ArkID 一账通内置插件:图形验证码认证因素的配置流程

    图形验证码认证因素插件功能介绍 图形验证码认证因素插件对用户认证凭证表单进行扩充,插入图形验证码并实现相关验证功能,是 IDaaS 一账通 ArkID 系统内置功能插件之一. 注意:图形验证码认证因素 ...

  7. 如何解决双因素和多因素身份认证的大问题

    在医学和最终用户网络安全中,第二个意见是一个好主意.双因素身份验证(2FA)和多因素身份证(MFA)是对抗涉及终端用户设备和基于互联网的服务的各种网络攻击的强大工具. 但是有一个大问题:很普遍地,人们 ...

  8. 玩转Spring Cloud Security OAuth2身份认证扩展——电话号码+验证码认证

    在程序的认证过程中,除了常规的用户名和密码方式(可以参考深入理解Spring Cloud Security OAuth2身份认证),也经常会出现电话号码+密码的方式:电话号码+验证码的方式:或者第三方 ...

  9. 什么是双因素身份认证?

    通常身份认证的方式主要包括: (1)某人知道什么(如口令.答案等), (2)某人拥有什么(如令牌.钥匙等), (3)某人的身份特征(如指纹.虹膜等) 以上其中任意2种组合即为双因素身份认证. 如APP ...

最新文章

  1. Android开源项目源码下载(不断更新中)
  2. python中的for else
  3. 网页标题设置,为什么在SERP中,显示结果不一致?
  4. Android倒计时工具类
  5. win c语言创建线程,初学者 CWinThread 线程类
  6. 左程云 Java 笔记--暴力递归--动态规划
  7. 天龙八部手游服务器维护公告,天龙八部手游 近期更新维护公告
  8. tahoma字体对中文字的影响
  9. 学习漫画应该如何入门?其实掌握这5种漫画套路就可以啦
  10. win32原生API实现OpenGL例子(无glew,glut等第三方依赖库)
  11. 使用Jquery制作精美的图片展示效果
  12. Android 仿朋友圈单张图片限定宽高超出时按比例缩放效果实现
  13. 无人机开发-图传技术浅析
  14. 爬虫系列,(4),playwright使用说明
  15. MATLAB新手简明使用教程(七)——使用matlab建立多项式以及求导,商求导乘积求导等——新手来看,保证看懂。
  16. 攻防世界-reverse-easyRE1
  17. QML地图中使用MapItemView
  18. 简历被肆意贩卖,个人信息安全何在?
  19. 广东外语外贸大学计算机考研资料汇总
  20. 模糊的正确和精确的错误

热门文章

  1. 手机腾讯网前端框架MT2.1.0发布
  2. ams1117 lm317 对比_浅谈LM1117输入电流和输出电流的差异
  3. 使用PWM信号实现呼吸灯(IDE+Protuse)
  4. 一维地震子波合成记录c语言,地震子波波形显示及一维地震合成记录
  5. mov 和 mp4 格式的区别
  6. 一名投资客手写MT4爆仓现价
  7. 关闭华为的触摸屏+查看自己电脑主板型号顺便推荐了个全能检测工具+进入华为的bios看看
  8. 跟潭州学院的强子老师学习网络爬虫---爬取全书网
  9. 计算机中的物理知识点总结,有关初中物理电磁波章节知识点总结
  10. 基于FPGA的多路彩灯设计及代码