企业内部应用
什么是第三方登录?
现如今微信登录已经成为了登录体系的标配,人们越来越不习惯去记忆这些繁琐的帐号密码,取而代之的是点击跳转到微信进入到APP中去授权登录。通常把这类通过第三方授权登录自家产品的方式,统称为第三方登录。
那么,什么是企业内部应用呢?
企业内部应用一般是用来服务于企业员工的应用,一般在大型企业中才会有存在价值,如企业班车应用、企业新闻应用、企业差旅应用等,它们有一个共同点就是必须使用员工工号登录后才能使用。在有了第三方登录概念之后,是否也可以将登录模块设计为在别的APP上获取完登录态之后返回即可使用这种形式呢?答案是肯定的。因此需要类似于华为的WeLink、平安的快乐平安这类的宿主APP来提供登录认证,获取到员工信息之后回传给那些唤起的应用,如此一来这些应用不需要关心登录模块的开发和登录态的打通,只需要集成集团登录SDK和配置一些信息即可。
既然实现方式与第三方登录类似,那么就以大家熟悉的第三方登录作比,能更清楚地说明问题。
Scheme跳转机制
要实现第三方登录,首先得提供一种方式让其他应用将本应用唤起,在iOS里是通过Scheme实现的。Scheme是iOS的一个特性,它可以将应用自身绑定到一个自定义的URL Scheme上,之后就可以通过浏览器或其他应用来启动本应用。
我们都知道"https://www.baidu.com"就是一个URL,也叫链接或网址,在浏览器输入该URL便可以进入百度首页;同样地,将应用绑定Scheme之后也可以使用浏览器唤起该应用,如在浏览器中输入"weixin://"会唤起微信APP,输入"sms://"则会唤起系统的短信APP。设置应用Scheme时必须唯一标识这个应用,如果你设置的Scheme与别的应用冲突了,你的应用不一定会被唤起。因为当应用安装时系统会注册你应用的Scheme,一般情况下会先调用先注册该Scheme的应用,当然系统级应用的优先级是最高的。所以我们定义Scheme时应尽量避开系统已经定义过的Scheme。
那么如何自定义Scheme呢?
在 TARGETS -> Info -> URL Types 点击添加
如此一来,该应用就绑定了hostApp这个Scheme,当应用被安装之后,在浏览器中输入"hostApp://"则会唤起该应用。
微信登录流程
微信登录其实也没那么复杂,主要包括调起微信APP和微信授权之后返回原应用这两个步骤。
如何调起微信APP前面已经介绍过Scheme,很显然微信在自己的SDK里集成了"weixin://"这个Scheme之后就可以轻松将自身调起,之后暴露个公共方法将scope、openid及appid等信息传过去,就可以很容易获取到唤起应用的注册信息及需要获取的权限,并拉起微信去授权登录页等待用户授权。
至于用户授权后如何返回原应用其实也很简单,微信接入文档会要求接入应用将bundleID绑定Scheme供微信回跳。iOS有个机制,当其他应用将自身唤起时会进入下图这个方法:
观察上图不难发现通过UIApplicationOpenURLOptionsSourceApplicationKey这个Key值可以很轻松拿到调起应用的bundleID,那么当调起应用的Scheme绑定自身bundleID之后,微信就可以轻松返回到原应用了。
同样地微信回跳到原应用之后也会唤起上图那个方法,此时需要在这个方法里调用微信SDK提供的handleOpenURL:delegate:
方法让微信处理一些内部逻辑,我们只需在onResp:
回调里处理自己的逻辑即可。
以上就是授权登录的全流程,至于如何获取accessToken及用户信息事实上都是通过接口调用获取的,未授权时应该也可以调用接口,但是应该会提示没有用户权限的返回错误。所以说授权只是个打开权限的过程,跟获取accessToken和用户信息是相对独立的流程。
Keychain实现应用间数据共享
Keychain是iOS的一个相对独立空间,当应用被替换或者被删除时并不会影响Keychain中的内容,相对于NSUserDefaults等其他保存方式,Keychain更为安全。所以我们会用Keychain保存例如密码、证书、UDID等一些比较私密的信息。
对每一个应用来说,Keychain都有两个访问区,私有区和公共区。私有区存储的任何数据其他应用程序无法访问,公共区存储的内容可以实现多个应用程序间的共享,但是他们得有相同的公共区名称,官方文档称之为"keychain access group"。本文将着重对这一部分进行介绍。
要实现不同应用共享Keychain中的数据,首先要声明Keychain公共区名称。在Project -> Capebilities -> Keychain Sharing,将开关打开,如下图:
在上图的Keychain Groups填上这个公共访问存储区名称。同样地,其他应用保持与该应用持有相同的Keychain Groups,那么这两个应用就可以通过这个公共访问存储区名称实现数据的共享。
我在第一个应用做了一个UITextField,并在这textField随便输入一串字符串,在textField的textFieldShouldReturn
回调事件中使用Keychain将其存储:
在上面提到的另一个有相同Keychain Groups名称的应用通过Keychain读取出来:
观察日志,当textField第一次输入1234567890时读取到的日志为:
将1234567890改写为9876543210再次执行读取Keychain,读取到的日志为:
可见,通过Keychain Groups这个桥梁实现了两个应用间的数据共享。
登录模块设计思路
了解到上面的知识后,接下来要介绍的就是如何使用这些知识来设计企业内部应用登录模块了。
外输SDK设计
首先我想象的场景是在SDK里封装好一个基本的网络请求,在请求完成回调里判断错误码,若该错误码是已定义好的code,则唤起宿主APP登录页。当然不使用SDK提供的网络请求也可以,只需提供唤起宿主APP登录页的方法即可。
根据以上思路开始进行SDK设计,首先封装网络请求类PARequest:
这里不涉及具体网络请求,只在于说明了一个唤起宿主APP登录页的时机,当错误码匹配时调用PAUtility工具类的loginWithHostAPP方法:
可以看到,唤起方法很简单,就像上面所说只需知道宿主APP的Scheme,然后执行hostApp://即可。至于后面拼接的backUrl是回跳的Scheme,集成SDK时需修改配置文件填入相应的信息,像这样:
如此一来,SDK集成进去之后便可以通过配置文件获取到原应用配置信息,并将信息传递给宿主APP,backUrl的工作方式就是这样。
至此,一个简易的SDK封装完毕,之后就是将这些文件打包成静态库/动态库的工作,这里就不作过多介绍了。
宿主APP设计
宿主APP无非只需要做三件事情:
1、存储原应用带过来参数,并调起登录页面;
2、登录成功将登录态等信息存入Keychain;
3、从存储信息中取出参数回跳至原应用。
存储原应用带过来参数,并调起登录页面
前面提到过当应用被唤起时会调用系统方法application:openURL:options:
,可以在这个方法对原应用参数进行存储,并唤起hostAPP的登录页面:
将登录态等信息存入Keychain
前面提到过要实现数据在应用间共享,需通过Keychain实现。首先需要设置Keychain Groups:
设置成功后可通过Keychain实现数据共享,在登录成功后使用Keychain存储数据:
这里忽略登录具体的业务逻辑,只展示Keychain存储代码。
回跳至原应用
从上图看到登录成功后会执行delegate,可以在这个代理执行回跳逻辑。由于第一步已将回跳Scheme存储起来了,所以回跳代码相对简单:
至此,宿主APP设计完毕。
企业应用集成SDK
集成步骤也相对简单,只需四步即可。
1、设置应用Scheme:
2、设置Keychain Groups:
3、集成SDK并配置所需参数:
4、处理回调:
至此,SDK集成完毕,使用SDK提供的网络请求即可:
当捕获到特定错误码时会自动唤起宿主APP登录页。
总结
此设计其实就是源于第三方登录,只不过加了一些企业应用特有的东西,例如Keychain Groups、配置文件等,使得参数配置和数据传递更为简便,不需要像微信那样授权后还要使用请求来获取accessToken及用户数据等信息。
以上仅为Demo设计,还有很多细节尚未完善。如宿主APP是如何知道唤起的登录页是外部APP还是还是自身APP、当通过Scheme将原应用的多个参数传递到宿主APP时又应如何解析参数等。不过这些小细节肯定都有相应的解决方案,这里就不作过多讨论了。