Web应用多账号系统设计及微信扫码登录实现
Web应用多账号系统设计及微信扫码登录实现
1 前言概述
公司对功能测试,性能测试,安全测试等等都做了比较好的自动化后,急需要一个MIS系统来统一管理这些结果及报表。
此MIS系统特点如下:
- 仅内部人员使用
- 部署在公网
基于如上特点,显然让公司的人为这样一个内部系统而实现一个完整的账号不太现实,要兼顾隐私性和便捷性的需求,作者想到了使用微信扫码登录来做为身份认证,然后后台管理员审核,这样就可以达到如下的效果:
- 可以实现无门槛注册(微信扫一扫就完成注册),保证了便捷性
- 系统对未审核通过的人员进行隔离,保证了隐私性
然后在开发完毕此系统后,觉得有必要再总结而且小升华一下,于是就有了本文的写作动机。
2 多账号原理
本来本文的目的是 “实现微信扫码登录” ,但是后来觉得仅仅是为了实现这个功能,本文的立意又显得太低。所以就在此处扩展一下为 “多账号授权登录系统” 。
在近些年来,随着互联网越来越开发和协作,目前的系统登录方式也越来越多,已经远远超越了以前的单用户名的方式了。除了用户名密码外,一般网站还提供如下的登录方式:
- 第三方授权
-
- 微信/QQ/新浪微博(国内)
- Google/Facebook/Github(国外)
- 绑定账号
-
- 手机号
- 邮箱号
基于如上的几种登录方式,就形成了如下的 “多账号登录体系图”:

基本原理:
- 第三方授权
-
- 能够从可信第三方获取到相应的返回值(用户信息),然后和 user_id 绑定
- 不需要额外再输入密码便完成鉴权过程
- 会创建一组今后可以修改的 user_id 作为 占位用户
- 鉴权成功后设置session状态
- 绑定账号
-
- 事先已经完成了 user_id 的注册
- 完成了相应账号绑定,即表示认可和 user_id 均能登录
- 使用和 user_id 同样的或者不同的密码体系(一般使用相同密码)登录完成鉴权
- 鉴权成功后设置session状态
关于 绑定账号 的方式比较简单,此处就不再赘述。
基于 第三方授权 的方式,则比较精妙,可学习性比较强,因为基于互联网越来越开放的特性,此方式肯定会越来越多的被应用,越来越成为主流。下面将以 微信扫码 授权登录为例子来进行讲解。
3 扫码登录逻辑
使用 微信扫码 授权登录的逻辑图如下:

其中主要处理的事情如下:
- 向第三方发起鉴权请求
- 第三方鉴权回调
- 和MIS系统本地 user_id 体系关联(新建用户)
- 设置session登录状态
- 处理不同结果的显示界面
4 微信扫码过程
使用过微信扫码登录系统的人会有如下的过程体验(以著名社交网站 知乎 为例子):
- 打开 知乎 主页,点击 “微信登录” 的图标
- 浏览器重定向到微信域(见下图标记1)下面的二维码页面
- 用户掏出手机打开微信,扫一扫
- 在手机微信上点击授权
- PC上面的二维码页面显示授权成功,并转向到 知乎 首页,认证成功
整个过程对于终端用户来说,只有短短几秒,而且不用输入任何密码,可以说是一种非常安全又便捷的体验。
那么问题来了,通过微信扫描二维码,并完成MIS系统注册登录这个短短几秒的时间里面,到底发生了哪些事情?
通过浏览器抓包,对几个关键通讯过程进行分析。

PC浏览器会依次发起两个长连接(比较长时处于 pending 状态)的请求:
- 等待手机端的微信扫码(上图标记2)
- 等待手机微信点击 “确认登录” 按钮(上图标记3)
这两个状态都会反馈到PC端的二维码页面,在手机端完成确认后,PC浏览器上面的页面就会生定向到授权后的页面(如 知乎 首页)。
具体各方通讯时序图如下:

上图对整个过程中通讯涉及的对象进行了清楚的描述,关于上图数字标注部分注解如下:
- 网站服务器向微信API传入带有 回调url 的参数
- 手机微信通过摄像头扫二维码,从 光学原理 上完成数据的传递
- PC浏览器上查询扫码状态的长连接收到返回的状态值,并更新提示
- PC浏览器上查询手机客户端点击确认按钮的状态值,并更新提示,然后重定向到 过程1 中传递url地址上
- 网站服务器在授权成功后,完成本系统的用户注册或者登录的业务逻辑
- 网站服务器重定向到用户登录成功的界面中(如果对于新注册用户不需要额外的审核的话)
关于微信扫码认证部分的开发,本文不再赘述,只给出如下注意事项:
- 微信平台的各种API接口请参考:微信开放平台提供的官方文档
- 微信扫码登录的开发权限需要在微信开放平台中进行企业资质认证(个人用户无法获得)
- 回调url 的域必需在微信开放平台中进行填写备案,本地开发时传递的 回调url 参数必须和备案一致
5 代码实现
根据如上原理,最后将提供具体实现代码以供参考 ,为了简洁,有一些通用的工具函数的具体实现就不贴出来了。
使用 python3.5 实现 微信扫码登录Web应用程序 的参考代码如下所示。
对应 上图标识1 中的代码实现:
class WeChatAuth(MyBaseHandler):
"""
点击后直接重定向到微信登录界面 - wechat QR扫码登录,web端
- 直接重定向到微信的页面
""" def get(self):
state = get_uuid1_key() # 生成唯一的码 wx_qr_param = dict(
appid=wx_webapp.appid,
# redirect_uri=wx_webapp.qr_auth_cb_url,
redirect_uri='http://your.domain.com/wechat/wechat-auth-callback/',
response_type='code',
scope=wx_webapp.login_scope,
state=state
) ##wechat_redirect wx_qr_url = 'https://open.weixin.qq.com/connect/qrconnect?%s#wechat_redirect' \
% urllib.parse.urlencode(wx_qr_param) self.redirect(wx_qr_url)
对应 上图标识5 中的代码实现:
class WeChatAuthCallback(MyBaseHandler):
"""
微信第三方认证之后,开始将此用户在本系统沉淀下来 - 用于微信服务器传回code的值
- 此处要再请求获得access_token
""" async def get(self):
wx_code = self.get_argument('code', '')
wx_state = self.get_argument('state', '') if wx_code == '':
res = ConstData.msg_forbidden
dlog.debug(res)
self.write(res)
return dlog.debug('wx_code:%s,wx_state:%s' % (wx_code, wx_state)) access_token_res = wx_webapp.get_auth_access_token(code=wx_code, state=wx_state)
user_info = wx_webapp.get_auth_user_info(auth_access_token_res=access_token_res)
""":type:WeChatUser""" # 微信返回的用户信息串 if user_info is None:
res = ConstData.msg_forbidden
dlog.debug(res)
self.write(res)
return wechat_user = await MisWeChatUser.objects.get(openid=user_info.openid, unionid=user_info.unionid)
""":type:MisWeChatUser"""
# 一个Open_id下面所有的id都是靠union来区分账号 if wechat_user is not None:
user = await User.objects.get(user_id=wechat_user.user_id)
assert user is not None
if user.active:
if await user.is_online():
await self.update_session() # 更新时间
else:
await self.create_session(user) # 新增加一个session
self.write('in authorized page')
# self.redirect('/') # todo 重定向到登录授权后的主页
return # 如果不存在wechat备案信息,则需要备案wechat信息,而且新注册初始账号
default_new_user_id = 'u_' + get_uuid1_key() new_wechat_user = MisWeChatUser(
openid=user_info.openid,
nickname=user_info.nickname,
unionid=user_info.unionid,
# user_id=wx_webapp.appid + '_' + user_info.unionid, # 通过微信号登录生成的一个唯一的用户名,后面可以提供修改
user_id=default_new_user_id,
appid=wx_webapp.appid
)
new_wechat_user.set_default_rc_tag() # rand_salt = get_rand_salt()
new_user = User(
user_id=default_new_user_id,
# salt=rand_salt, # 防止别人md5撞库反向破解的随机数
# passwd=StringField() # 密码,通过第三方登录的默认不设置
first_name=user_info.nickname,
status=FieldDict.user_status_init, # 表示是可更改状态
active=False,
)
new_user.set_default_rc_tag() await new_wechat_user.save()
await new_user.save()
self.write('in unauthorized page') # self.redirect(URL_ROOT) # todo 导入到未授权的页面
6 功能测试
设计两组测试用例。
检查微信用户扫码后能否完成上述流程:
- 用A微信账号扫码登录,查看是否自动注册
- 是否提示重定向到 “未授权页面”
在数据库中修改A微信自动注册的用户状态为审核通过后再扫码登录:
- 修改A用户状态为 active=True
- 是否提示重定向到 “授权页面”
- 是否在数据库中看到登录的session状态
测试截图如下:

7 小结
如果我是一个产品经理,如果我做一个web应用的产品,那么在产品早期阶段,我肯定会选择微信登录的方式,因为这种方式的登录门槛实在是太低了,用户试用产品的门槛也降到了最低,后续的活跃程度至少不会受到登录的门槛的影响。
可惜,还有好多产品经理不懂这个,这么重要的入口都没有稍微花点心思去打磨。
| 作者: | Harmo哈莫 |
|---|---|
| 作者介绍: | https://zhengwh.github.io |
| 技术博客: | http://www.cnblogs.com/beer |
| Email: | dreamzsm@gmail.com |
| QQ: | 1295351490 |
| 时间: | 2016-02 |
| 版权声明: | 欢迎以学习交流为目的读者随意转载,但是请 【注明出处】 |
| 支持本文: | 如果文章对您有启发,可以点击博客右下角的按钮进行 【推荐】 |
Web应用多账号系统设计及微信扫码登录实现的更多相关文章
- 微信开放平台开发——网页微信扫码登录(OAuth2.0)
1.OAuth2.0 OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用. 允许用户提供 ...
- 第三方登录:微信扫码登录(OAuth2.0)
1.OAuth2.0 OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用. 允许用户提供 ...
- php微信开放平台--第三方网页微信扫码登录(OAuth2.0)
第一.OAuth2.0 OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用. 允许用户提 ...
- C#开发微信门户及应用(45)--微信扫码登录
在前面随笔<C#开发微信门户及应用(41)--基于微信开放平台的扫码登录处理>介绍了基于微信开放平台接口实现的微信扫码直接登录的过程.本篇介绍对扫码登录的一些改进和处理,以便更方便应用在实 ...
- Vue+abp微信扫码登录
最近系统中要使用微信扫码登录,根据微信官方文档和网络搜索相关文献实现了.分享给需要的人,也作为自己的一个笔记.后端系统是基于ABP的,所以部分代码直接使用了abp的接口,直接拷贝代码编译不通过. 注册 ...
- PHP对接微信扫码登录
1.PC端扫码登录 如果你将微信小程序和公众账号绑定同一个微信开放平台,那么他们各自的接口返回有一个参数unionid是相同的(没有绑定微信公众账号就没有):那么你就可以使用这个unionid来做业务 ...
- 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_5-6.微信扫码登录回调本地域名映射工具Ngrock
笔记 6.微信扫码登录回调本地域名映射工具Ngrock 简介:讲解微信扫码回调本地域名ngrock讲解 1.为什么要用这个,微信扫码需要配置回调,需要配置对应的域名 ...
- Android (微信扫码登录) 获取微信二维码+扫码登录
话不多说 直接上菜! 一.因为是微信扫码登录,所有要在微信开放平台 微信开放平台 (qq.com) 进行注册----- 如下 1.资源中心 里面也有详细的官方讲解,里面也有demo 可以下载 2 ...
- Tapdata Cloud 2.1.2 来啦:大波细节已就绪!字段类型可批量修改、支持微信扫码登录、新增支持 Vika 为目标
Tapdata Cloud cloud.tapdata.net 让数据实时可用 Tapdata Cloud 是国内首家异构数据库实时同步云平台,目前支持 Oracle.MySQL.PG.SQL Ser ...
随机推荐
- 如何一步一步用DDD设计一个电商网站(二)—— 项目架构
阅读目录 前言 六边形架构 终于开始建项目了 DDD中的3个臭皮匠 CQRS(Command Query Responsibility Segregation) 结语 一.前言 上一篇我们讲了DDD的 ...
- ASP.NET从零开始学习EF的增删改查
ASP.NET从零开始学习EF的增删改查 最近辞职了,但是离真正的离职还有一段时间,趁着这段空档期,总想着写些东西,想来想去,也不是很明确到底想写个啥,但是闲着也是够 ...
- Oracle碎碎念~1
1. 设置SQL*Plus提示符 SQL> set sqlprompt "_user'@'_connect_identifier>" SYS@orcl> 为了对所 ...
- zookeeper源码分析之六session机制
zookeeper中session意味着一个物理连接,客户端连接服务器成功之后,会发送一个连接型请求,此时就会有session 产生. session由sessionTracker产生的,sessio ...
- Http请求
HTTP报文是面向文本的,报文中的每一个字段都是一些ASCII码串,各个字段的长度是不确定的.HTTP有两类报文:请求报文和响应报文. 请求报文 一个HTTP请求报文由请求行(request line ...
- 云瓣影音网站&&微信端(已开源)
随着该项目的发布到线上(小打小闹),即将又要开启另一段崭新的旅程.强迫自己停下来写写所学所得,个人认为总结和分享是一种很棒的学习方式.那让我们先来瞧瞧项目长的什么样.如果着急要源码的朋友,可以下拉到最 ...
- js数组去重几种思路
在一些后台语言中都内置了一些方法来处理数组或集合中重复的数据.但是js中并没有类似的方法,网上已经有一些方法,但是不够详细.部分代码来源于网络.个人总计如下:大致有4种思路 1)使用两次循环比较原始的 ...
- 关键帧动画:@keyframes
关键帧动画:@keyframes: <!DOCTYPE html> <html> <head> <meta charset="UTF-8" ...
- Eclipse出现"Running Android Lint has encountered a problem"解决方案
安装eclipse for android 时候的错误记录,转载自:http://blog.csdn.net/chenyufeng1991/article/details/47442555 (1)打开 ...
- iOS 10 跳转系统设置
苦心人天不负, 为了项目终于把 iOS 10 跳转系统设置的方法给搞定了, 很欣慰. http://www.cnblogs.com/lurenq/p/6189580.html iOS 10 跳转系统设 ...