以前总是在群里或者网上听说什么:单点登录,免密登录,因为没有听过,所以感觉很高大上的样子,最近一次免密登录的开发需求,差点给自己打脸了………
前言:
- 最近公司要开发一个免密登录的需求,以前好像听过,感觉没撒用处,就没有去管了。
- 因此不得不研究一下,原本以为会和某些第三方一样,各种配置,导入,各种坑,却没想到……哎!
背景
现在很多人在使用一个App的时候,遇到这样的一些问题:
- 经常需要输入账号密码,手动或者自动退出
- 如果账号或者密码一次输错又要重新输入,甚至各种验证。
- 有时候密码不太记得了,就要狠麻烦的修改或者找回
- 如果涉及到太多安全信息在里面,输入的时候可能会特别小心。
- ….
有了上面这些问题之后,自然也有很多公司或者技术人员考虑了很多技术或者涉及上的解决方案。其中免密登录被公认为是一种不错的选择,即使也有一些缺陷……
什么是:免密登录
免 密登录的意思 :
就 是 免 密认证,是利用了电信运营商独有的移动网络安全认证,实现手机号码认证登录、手机号码 就 是账号,无需设置密码,由运营商移动网络认证。
天翼
基于各行业的合作,天翼账号为合作方提供一套智能认证解决方案,”免密认证“和”运营商能力“:
- “免密认证”,依托电信运营商的移动数据网络,采用“通信网关取号”及SIM卡识别等技术,准确识别用户手机号码。依托运营商计费网络更“快,准,安全”。
- “运营商能力”,基于天翼手机用户的二次卡校验,实名校验,用户信用等多种基于运营商的特色功能。
移动
统一认证是中国移动推出的手机号码认证功能,应用集成后可通过数据网络、短信网关获取本机号码(覆盖移动、电信、联通手机号),实现手机用户免输账号密码一键注册/登录。
同时,应用可获取更多用户授权的号码信息,调用更多的用户身份认证功能。如:本机号码校验、号码状态查询、二次卡查询、实名认证、防刷单、互联互通等服务。
由于天翼帐号免密登录在移动号码上的成功率不高,有些公司会考虑接入移动帐号免密登录来改善或者进行双重介入与验证判断(我们就是这做的)。
具体需求
- 当前手机无SIM卡/网络情况差,调用免密登录接口失败时,走短信登录流程;
- 有SIM卡且网络比较稳定,判断该手机号类型,
- 如果是移动卡,调用移动免密登录的接口,走移动帐号免密登录流程,
- 其他类型则调用移动免密登录的接口,走现有的天翼帐号登录流程。
- 当有双卡双待时,本机号码为启用了移动网络数据的那个。
核心代码
开发与操作流程
1. 运营商类型判断
定义枚举
typedef NS_ENUM(NSInteger, SSOperatorsType) {
// Apple NetworkStatus Compatible Names.
// 参考 https://en.wikipedia.org/wiki/Mobile_country_code
Other = 0, // 中国移动
Mobile = 1, // 中国联通
Unicom = 2, // 中国联通
Telecom = 3, // 中国电信
Tietong = 4 // 中国铁通
};
2. 库导入
#import <CoreTelephony/CTCarrier.h>
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
3. 类型获取
/**
获取运营商类型
@return 对应的运营商类型(枚举)
*/
+ (SSOperatorsType)getOperatorsType{
CTTelephonyNetworkInfo *telephonyInfo = [[CTTelephonyNetworkInfo alloc] init];
CTCarrier *carrier = [telephonyInfo subscriberCellularProvider];
NSString *currentCountryCode = [carrier mobileCountryCode];
NSString *mobileNetWorkCode = [carrier mobileNetworkCode];
if (![currentCountryCode isEqualToString:@"460"]) {
return Other;
}
// 参考 https://en.wikipedia.org/wiki/Mobile_country_code
if ([mobileNetWorkCode isEqualToString:@"00"] ||
[mobileNetWorkCode isEqualToString:@"02"] ||
[mobileNetWorkCode isEqualToString:@"07"]) {
// 中国移动
return Mobile;
}
if ([mobileNetWorkCode isEqualToString:@"01"] ||
[mobileNetWorkCode isEqualToString:@"06"] ||
[mobileNetWorkCode isEqualToString:@"09"]) {
// 中国联通
return Unicom;
}
if ([mobileNetWorkCode isEqualToString:@"03"] ||
[mobileNetWorkCode isEqualToString:@"05"] ||
[mobileNetWorkCode isEqualToString:@"11"]) {
// 中国电信
return Telecom;
}
if ([mobileNetWorkCode isEqualToString:@"20"]) {
// 中国铁通
return Tietong;
}
return Other;
}
4. 移动判断
/**
移动运营商类型判断
@return 布尔值(是否是移动运营商类型)
*/
- (BOOL)checkOperatorsTypeChinaMobile {
return [NetWorkState getOperatorsType] == Mobile;
}
具体实现代码(抽取封装之后的)
//免密登录
//1.本机手机号未注册过115帐号,则免密登录后自动注册、登录、绑定本机手机号。
//2.本机手机号已注册过115帐号,则直接登录该帐号。
//3.客户端判断当前启用移动网络数据的号码是否属于移动,
//属于则走移动免密登录流程,
//不属于则走现有的天翼免密流程
if ([[NetWorkState shareNetWork] checkOperatorsTypeChinaMobile]) {
///移动接口接入地址 http://dev.10086.cn/wiki/?p5_01_03#p2-2
[UMCOpenLogin loginExplicitly:self complete:^(id sender) {
if ([sender[@"resultcode"] isEqual:@"000"] && sender[@"uniqueid"] && sender[@"accesstoken"]) {
[MBProgressHUD showLoading:NSLocalizedString(@"正在登录...",nil)];
[COLoginService noCodeLoginWithToken:sender[@"accesstoken"] uniqueId:sender[@"uniqueid"] block:^(id _Nonnull model, NSError * _Nonnull error) {
[MBProgressHUD hide];
}];
} else if(![sender[@"resultcode"] isEqual:@"102121"]) {
[self smsVerifyCodeLogin];
}
}];
} else {
///天翼接口接入地址 http://id.189.cn/api?initialSrc=/html/api_detail_447.html
[EAccount login:@"" loginWay:@"zm|dm" accountType:@"" loginList:@[] hasat:NO hideTop:NO baseApp:YES basicLoginTxt:@"短信登录" controller:self success:^(NSDictionary * _Nonnull resultDic) {
if (resultDic[@"accessToken"]) {
[MBProgressHUD showLoading:NSLocalizedString(@"正在登录...",nil)];
[COLoginService noCodeLoginWithToken:resultDic[@"accessToken"] uniqueId:nil block:^(id _Nonnull model, NSError * _Nonnull error) {
[MBProgressHUD hide];
}];
}
} failure:^(NSError * _Nonnull error) {
NSLog(@"error%@", error);
if (error.code == -8994014) {
[self smsVerifyCodeLogin];
} else {
[MBProgressHUD showError:error];
}
}];
}
免密登录后的流程
- 获取用户信息
通过获取用户信息接口,在用户登录后可以获取用户昵称、手机号码、头像等信息,需要对接获取用户信息接口.
刷新accessToken
accessToken是调用账号登录的调用凭证,accessToken有效期为1个月
在有效期内避免accessToken过期后,可以在用户打开应用时使用刷新accessToken接口进行刷新.
相关API:
登录相关接口
这里只介绍一下登录相关,其他Api可自行查阅API文档和源代码
天翼API:
/**
打开登录页面
@param showThirdLogin 第三方登录的配置,有qq,微博,微信三个,要哪个登录方式,就传对应的拼音,如@"qq" 或者@"qq|weixin" 或者@"qq|weixin|weibo"
@param loginWay 登录方式,zm、dm、zm|dm、dm|zm等4种方式,zm代表账号密码登录,dm,代表短信验证码登录,zm|dm代表两种都有,并且优先账号密码登录, dm|zm代表两种都有,优先短信登录
@param accountType 账号类型,有mobile,email两种,两种都要的话,传@"mobile|email",否则传@"mobile" 或者@"email"
@param loginList 已经登录上的账号的accessToken组成的数组,不需要多账号功能的,可以传一个空的数组
@param hasat 登录页面的登录账号是否默认加上@189.cn,yes表示有后缀,no表示没有后缀
@param hideTop 是否隐藏头部导航栏
@param baseApp 自定义账号入口方式
@param basicLoginTxt 自定义账号入口方式的自定义文本 (6到8个字符)
@param controller 可以为nil,如果是nil,SDK会新建一/Users/thy/TY/EAccountSDK_WIFI/EAccountSDK/EAccountSDK/EAccount.h个window来加载登录页面,如果不是空,SDK会使用controller来preszent登录页面。
@param success 登录成功的回调
@param failure 登录失败的回调
*/
+ (void)login:(NSString *)showThirdLogin
loginWay:(NSString *)loginWay
accountType:(NSString *)accountType //
loginList:(NSArray *)loginList
hasat:(BOOL)hasat
hideTop:(BOOL)hideTop
baseApp:(BOOL)baseApp
basicLoginTxt:(NSString *)basicLoginTxt
controller:(nullable UIViewController *)controller
success:(successHandler)success
failure:(failureHandler)failure;
移动API:
/**
显式登录
*/
+ (void)loginExplicitly:(UIViewController *)vc complete:(void (^)(id sender))complete;
总结
- 免密登录主要体现在安全性上,手机丢了,那么就麻烦大了,
- 而且现在的黑科技太发达了,短信截获、伪装基站、伪装商家服务号、复制SIM 卡…… 用手机号登录、用短信验证码的方式真的安全吗?!