前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS-Swift 完整登录方案(touchID&faceID& keychain)一iOS-Swift 完整登录方案(touchID&faceID& keychain)一

iOS-Swift 完整登录方案(touchID&faceID& keychain)一iOS-Swift 完整登录方案(touchID&faceID& keychain)一

作者头像
用户8893176
发布2021-08-09 14:32:46
1.9K0
发布2021-08-09 14:32:46
举报
文章被收录于专栏:小黑娃Henry小黑娃Henry
前提:所有所有代码都是基于iOS9及以上。
最近app的登录部分需要重新梳理,而且产品爸爸提了些要求。代码已经提测空出一点时间自己整理一下。需要实现的需求如下:
  1. 首次登录使用密码或第三方登录
  2. 登录完成后开启生物验证
  3. 对已开启生物验证的用户可免密登录
  4. 可使用多设备登录
  5. 用户token密文传输(RSA加密)
  6. 可在无网络的情况下个人信息的展示
需求整理完之后我想说产品你(n)真(m)棒(m)呀(l)。登录模块一次到位也好,我们对需求进一步分析。涉及到知识点:
  1. 接入三方登录(友盟等平台有成熟的方案,不是本文讨论的重点)
  2. touchID、faceID
  3. keychain
  4. RSA加密
  5. 本地缓存,安全起见我选择NSKeyedArchiver(归档)
明确了目标就开始搞,我打算先一部分一部分搞,最后在把逻辑串起来,这操作也完全符合面向对象的思路~

接入三方登录

推荐友盟:https://www.umeng.com/

简单介绍一下流程:

  1. 三方登录成功后会返回一个uid、access token;
  2. 若已经绑定过手机号则返回用户token;
  3. 若首次登录则需要绑定手机号,绑定成功后返回用户token;
  4. 往后的流程和密码登录相同,开启生物验证,完成登录;

touchID、faceID

FaceID和TouchID本身代码很简单,使用起来也很容易,主要是逻辑的嵌套相对复杂。

代码实现篇幅较长,详细的介绍在这ios swift版touchID&faceID

  • 这就放一点核心代码
代码语言:javascript
复制
let authContent = LAContext()
        //如果为空不展示输入密码的按钮
    authContent.localizedFallbackTitle = strTips
    var error: NSError?
    if authContent.canEvaluatePolicy(
    .deviceOwnerAuthenticationWithBiometrics, error: &error) 
    {        authContent.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: strTips) {(success,error) in
    if success {
        //evaluatedPolicyDomainState 只有生物验证成功才会有值
        if let _ = authContent.evaluatedPolicyDomainState {
            //如果不放在主线程回调可能会有5-6s的延迟
            DispatchQueue.main.async {
                print("验证成功")
                block(.success, error)
            }
        }else{
            DispatchQueue.main.async {
                print("设备密码输入正确")
            }
        }
    }else{
        guard let laError = error as? LAError else{
            DispatchQueue.main.async {
                print("touchID不可用")
                block(.touchidNotAvailable,error)
            }
            return
        }
        switch laError.code {
        case .authenticationFailed:
            DispatchQueue.main.async {
                print("连续三次输入错误,身份验证失败")
                block(.failed, error)
            }
                     。。。。。。还有很多其他类型

keychain

企业微信截图_ae4304c6-9874-4f24-8bb9-333b82556c7d.png

首先在xCode中打开对应选项。

本方案中只涉及到了keychain的基本使用,所以在这里就不多介绍。在代码中有一个keychain的工具类可以直接使用。

NSKeyedArchiver

这个也是iOS中比较基础的数据本地化方案,因为Apple对数据会做加密然后写成文件,安全性相对较高,个人信息推荐使用这种方式来缓存。(注:有些极少数用户会选择越狱,你保存的信息就会成明文信息),

  • 使用有一点需要注意,所缓存的对象一定要遵守NSCoding协议,且该协议无法在extension中使用.如果大量使用归档建议使用runtime来进行归解档
代码语言:javascript
复制
public var userId:Int?
func encode(with aCoder: NSCoder) {
    aCoder.encode(self.userId, forKey: "userId")
}
required init(coder aDecoder: NSCoder) {
    self.userId = aDecoder.decodeInteger(forKey: "userId")
}

在iOS11以后API有个比较大的修改需要适配。而且使用了新的API归档就必须使用新的API解档。一定要注意这个坑我补了好久,放出最基本的代码

代码语言:javascript
复制
//归档
if #available(iOS 11.0, *) {
    do {
        let data = try NSKeyedArchiver.archivedData(withRootObject: objc, requiringSecureCoding: false)
        do {
            try data.write(to: URL(fileURLWithPath: path))
        } catch {
            assert(true, "无法写入path")
            return false
        }
    } catch {
        assert(true, "无法生成归档数据")
        return false
    }
}else{
    return NSKeyedArchiver.archiveRootObject(objc, toFile: path)
}
//解档
if #available(iOS 11.0, *) {
    do{
        let data = try Data.init(contentsOf: URL(fileURLWithPath: path))
        do{
            return try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data)  as AnyObject
        } catch {
            assert(true, "用户数据解档失败")
        }
    } catch {
        assert(true, "用户数据解档路径错误")
    }
}else{
    return NSKeyedUnarchiver.unarchiveObject(withFile: path) as AnyObject?
}

RSA加密

由于涉及到了密码登录,按要求密码不能明文传输。最终选择使用RSA来进行加解密。现在很多APP都是手机验证码登录应该就不涉及到加密问题,就可以跳过了,按需索取吧。

本人试过很多版本,也尝试着去了解RSA这个非对称加密,在iOS系统中用Security库来实现加密算法。

其实只要了解该加密算法是使用一对秘钥,公钥是用来加密的,私钥是用来解密的就好了。

只要使用pod来引入就可以了,该库也是使用swift编写的。

代码语言:javascript
复制
   pod 'SwiftyRSA'

依旧是核心代码,没什么好解释的.

  • 需要注意秘钥字符串必须使用base64编码。
代码语言:javascript
复制
let publicKeyRef = try PublicKey(base64Encoded: publicKey)
let clear = try ClearMessage(string:passWord, using: .utf8)
//PKCS1 / PKCS8 与秘钥生成时相同
let encrypted = try clear.encrypted(with: publicKeyRef, padding: .PKCS1)
let RSAPassWord = encrypted.base64String

这是工具类的准备,逻辑实现由于篇幅的原因就新开一篇了。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019/6/6 下午,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前提:所有所有代码都是基于iOS9及以上。
  • 最近app的登录部分需要重新梳理,而且产品爸爸提了些要求。代码已经提测空出一点时间自己整理一下。需要实现的需求如下:
  • 需求整理完之后我想说产品你(n)真(m)棒(m)呀(l)。登录模块一次到位也好,我们对需求进一步分析。涉及到知识点:
  • 明确了目标就开始搞,我打算先一部分一部分搞,最后在把逻辑串起来,这操作也完全符合面向对象的思路~
相关产品与服务
验证码
腾讯云新一代行为验证码(Captcha),基于十道安全栅栏, 为网页、App、小程序开发者打造立体、全面的人机验证。最大程度保护注册登录、活动秒杀、点赞发帖、数据保护等各大场景下业务安全的同时,提供更精细化的用户体验。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档