智能小程序登录流程优化

小程序档案馆 - 登录授权

智能小程序运行在百度 App 之类的宿主上时,相比普通的 H5 应用有一项很大的优 势,就是可以调用宿主应用提供的各种 API 从而完成各种在 H5 实现比较困难的功 能,其中使用宿主的账号体系完成登录授权就是一项很重要的功能。

智能小程序在宿主应用中进行登录的方案是OAuth 2.0协议的变种,使用这种方案 进行登录的优势主要有以下几点:

某些小程序需要有一套用户体系来识别用户,进而提供对应的服务,但是往往 在用户注册这个环节上由于用户觉得麻烦而放弃使用,导致获取到的用户又流 失掉了。使用 OAuth 系的登录方式,智能小程序可以直接使用用户在百度 App 等宿主上的账号,用户登录了宿主的账号,就可以直接使用宿主账号在小 程序里登录。 

普通用户要记住自己在不同智能小程序中的用户名、邮箱、密码是一个比较困 难的事情,许多用户会选择在大多数应用中使用相同的用户名、密码等信息, 而这又容易导致某个应用的用户数据泄露后入侵者可以拿这些数据去尝试登录 其它智能小程序,从而入侵其它原本安全的应用,这种即是常见的“撞库”攻击。 使用 OAuth 系的登录方式,一般应用将用户登录的安全校验托管给提供OAuth 服务的应用,可以避免被“撞库”的风险,提高应用的安全性。

使用宿主账号体系进行登录

使用宿主的账号体系进行登录的全流程可见小程序开发文档中的登录章节,这里对使用此章节的内容进行登录做更详细的介绍。

获取 OpenID 和 SessionKey

在小程序的关联登录机制中,有两个非常重要的概念:

OpenID 是宿主为每个用户在每个小程序中生成的用户标识,一个相同的 OpenID 可以始终对应同一个宿主账号的用户。 

SessionKey 是宿主为每个用户在每个小程序中生成的数据密钥,数据密钥有 两个重要的作用:首先是通过宿主提供的接口获取到的数据会使用 SessionKey 加密,可以保证开发者服务端拿到的数据是真实有效的,其次是 SessionKey 会有更新机制,保证用户登录信息的安全。后面会在登录标识章节再详细讨论。

小程序获取用户的 OpenID 和 SessionKey 的流程图如下:

图中接口的详细参数可以参加开发者文档中的登录章节。

需要特别提到的一点是:swan.Login()不需要用户授权,也就是说在用户已登录 宿主账号的情况下整个流程是完全静默完成的,但是当用户在宿主应用上并未登录 的时候,调用此接口会弹出宿主应用的登录窗口,用户需要完成登录后再继续进行。 如果需要在用户未登录的时候做其它逻辑处理而不是要求用户登录,可以先通过 swan.IsLoginSync()判断用户的登录状态。

登录标识

当开发者获取到用户的 OpenID 和 SessionKey 之后,开发者应该生成一个唯一的 登录标识返回给小程序,并写到小程序的本地存储中,在后续的请求开发者的服务 端接口时通过参数带上这个唯一标识,供后端通过这个登录标识找到对应的 OpenID 和 SessionKey。

一种比较好的登录标识的设计范例是:Hash(OpenID + SessionKey + Salt),其中 Salt 是开发者自己定义的一个随机字符串,Hash 可以考虑使用 SHA1 或者 MD5 等碰 撞概率非常小的哈希函数。

一种非常不安全的方式是:直接使用 OpenID 或 SessionKey 的明文作为登录标识。 使用 OpenID 作为登录标识的风险在于:同一个账号的 OpenID 永远不会变,因此 若攻击者获取到某个用户的 OpenID,则可在参数中一直使用此 OpenID 来伪装成此 用户访问开发者的服务;使用 SessionKey 明文作为登录标识的风险在于,攻击者 不光可以直接使用此 SessionKey 解密用户数据,还可以使用它加密出假的用户数 据,然后通过开发者提供的服务端提口篡改用户的数据。

总结来说,登录标识需要满足:唯一性、有时效性,并不能带上敏感信息。

使用 SessionKey 处理用户数据

当获取到 SessionKey 和 OpenID 后,开发者就可以获取到有效的用户数据了。获 取用户数据主要有 swan.getUserInfo()和 swan.getPhoneNumber()等接口。下面

以 swan.getUserInfo()为例,讲解如何使用 SessionKey 安全有效地处理用户信息。

swan.getUserInfo()接口返回的内容可以分为明文和密文两部分,明文部分是为 了可以更快地显示在小程序的页面上,主要包括用户的头像、昵称等信息;密文部 分是 data 和 iv 两个字段。

以消息推送的场景为例,开发者可能需要在消息内容里以“亲爱的 XXX”为开头,此 时会用到用户的 OpenID 和真实的用户名。如果开发者提供一个接口,在通过 swan.getUserInfo()获取到用户信息后直接将用户信息以明文的方式发到开发者 自己的服务端某个接口中保存起来,就会出现一个安全问题:攻击者可以伪造用户 的名称等各种信息来访问开发者的服务器写入假的用户数据。

安全的做法是:开发者在前端获取到 swan.getUserInfo()后,将上一节中所说的 用户登录标识从 LocalStorage 中取出来,加上 data 和 iv,将这三个数据发到自己 的服务器,先通过登录标识将 SessionKey 取出来,然后用 SessionKey 和 iv 一起 使用 AES-192-CBC 算法对 data 进行解密(解密详细的过程及代码示例可参见用户数据的签名验证和加解密),通过判断解密是否成功,以及解密出的 OpenID 是否 与登录标识所关联的 OpenID 一致来判断数据的真实性,再保存到自己的数据库中。

特别说明一点,调用 swan.getUserInfo()这类接口会弹出授权提示框让用户进行 授权,若用户拒绝授权,再次调用此接口不会重复弹出授权提示框。开发者此时可 引导用户重新授权,并调用 swan.openSetting()让用户重新授权。

SessionKey 有效性判断

由上两节可知,开发者每次获取用户信息的时候,需要同时判断本地是否有用户标 识,以及 SessionKey 是否有效:若没有本地标识,则无法找到对应的 SessionKey; 而若 SessionKey 已经无效,说明开发者数据库中的用户 SessionKey 无法对宿主 所提供的 data 和 iv 进行解密。

判断 SessionKey 是否有效可以通过调用 swan.checkSession()来判断。如果为 false,则走上述获取 SessionKey 的流程重新让用户使用宿主账号在小程序内完成 登录;若为 true,则说明不用重新换取 SessionKey,可以直接获取用户信息。

需要注意的一点是,在提供多点登录的宿主应用(例如百度 App)中,有可能同一 个账号会在多台不同的设备上同时登录,此时有可能会出现此账号在多台设备上先 后都换取过 SessionKey,但是在此过程中 SessionKey 发生了变化,则变化前已换 取过 SessionKey 的设备上,本地存储中的登录标识已经失效(找不到对应的 SessionKey),而调用 swan.checkSession()仍然会得到 true,此时开发者应当在 登录标识已失效的设备上处理此类异常,重新换取 SessionKey 并生成新的登录标识。

未登录时的降级方案

由于宿主应用并不一定强制用户登录,因此用户也有可能处于未登录状态。此时开 发者可能不希望通过调用 swan.login()强制用户登录,而是希望直接使用用户的 设备标识来关联用户,存储一些非敏感的数据。因此智能小程序还提供一个 SwanID 的标识,可视作用户的设备标识。

SwanID 可以通过 swan.getSwanId()获取(接口文档)。SwanID 具有以下特征:

用户在同一台设备上使用同一个开发者所开发的不同智能小程序,得到的是相同的 SwanID。 

用户在同一台设备上使用不同开发者所开发的不同智能小程序,得到的SwanID 是不同的。

灵活地使用 SwanID 和 OpenID 进行搭配,可以做到许多特殊的功能,例如:

在未登录的时候,将数据与用户的 SwanID 关联,当用户登录后,通过 SwanID 找到用户登录前的数据,然后与 OpenID 关联,比如常见的场景例如电商类小 程序对购物车数据的同步。 

通过 SwanID 限定一个指定的 OpenID 只能在一台设备上使用某个小程序,即 当同一个 OpenID 先后出现了两个 SwanID 时,可以将前一个 SwanID 的登录态 踢出,比较常见的有 IM 类的小程序。

总结 

开发者可使用 OpenID+SessionKey 的方式使用宿主的用户体系完成自己的业 务需求。 

安全地处理 OpenID 和 SessionKey,不直接暴露到前端,而是基于它们生成用 户的登录标识,保证登录标识只在有效期内可用非常重要。 

当用户拒绝授权获取用户信息时,再次调用 swan.getUserInfo()方法无法重 新弹框让用户同意,此时可通过 swan.openSetting()方法让用户重新授权。 

当用户未登录时,可使用 SwanID 作为降级方案,处理一些不太敏感的业务。


智能小可爱 发布于2018-10-25 17:54 

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容

  • 0、杂记 0.1、在实际的开发中,图片资源不会存储在小程序的目录中,因为小程序的大小不能超过1MB(现在改为2M)...
    it筱竹阅读 5,209评论 0 10
  • 背景小程序一个比较重要的能力就是获取用户信息,也就是使用 wx.getUserInfo接口。我们发现几乎所有的小程...
    未央大佬阅读 15,315评论 0 23
  • 背景 微信小程序的使用可以快速的基于场景进行用户圈的建立推广,其中根据业务需要使用用户信息以及授权过程,主要用到的...
    极乐叔阅读 1,122评论 1 4
  • 转载链接 注:本文转载知乎上的回答 作者:初雪 链接:https://www.zhihu.com/question...
    pengshuangta阅读 28,306评论 9 295
  • 初中的时候上学,要坐半个小时的公交,春夏秋冬我都不分季节地赖床,于是早餐就固定下来,揣两个白水鸡蛋,再加一块站台旁...
    淣莫阅读 252评论 1 1