需求说明
1、线上保留授权登录,审核时添加帐号密码登录。
2、通过版本号来控制是否显示帐号密码登录。
需求地址
http://192.168.1.75/114la/230/114la_230/#g=1&p=9_0114%E5%95%A6%E5%B8%90%E5%8F%B7%E5%AF%86%E7%A0%81%E7%99%BB%E5%BD%95
核心代码
启动时根据该接口请求是否需要显示帐号密码登录的界面。
该接口需要获取客户端的版本号在URL中。
服务端判断客户端版本号如果大于服务端设定的版本号则返回114la_login_open=1.
static func get114LaBaseURL() -> String {
// return "http://114larc.com"
switch YYWApiCenter.getCurrentAPIEvironmentState() {
case .rc:
return "http://114larc.com"
case .gray:
fallthrough
case .release:
return "https://114la.com"
}
}
//MARK: 检查是否打开114啦登录开关Api
static func getCheckOpen114laLoginApi() -> String {
return get114LaBaseURL() + "/q/api" + get114LaCommonVersion() + "/checkVersion"
}
// MARK: - 检查是否打开114啦帐号登录开关
static func checkShouldOpen114laLogin() {
let request = Request()
request.apiURL = YYWApiCenter.getCheckOpen114laLoginApi()
request.apiResource = ""
request.getAsyncWithCompleteHandle { (json, error) -> AnyObject? in
if let json = json {
yywDonUseNewAuthLogin = json["114la_login_open"].intValue != 1
UserDefaults.standard.set(!yywDonUseNewAuthLogin, forKey: "yywDonUseNewAuthLogin")
}
return nil
}
}
有个全局的方法是根据yywDonUseNewAuthLogin来选择创建哪个登录控制器。
func chooseLoginVC() -> UIViewController {//判断接口开关 跳转不同登录界面.
if yywDonUseNewAuthLogin {
//无帐号密码登录的
return AuthViewController(nibName: String(describing: AuthViewController.self), bundle: nil)
} else {
//有帐号密码登录的
return NewAuthViewController(nibName: String(describing: NewAuthViewController.self), bundle: nil)
}
}
帐号密码登录界面因为键盘弹起后iPhone部分内容横屏会显示不下。
因此该界面限制的屏幕的方向为竖屏。不允许横屏。
//强制iphone竖屏
var canAutorotate = true
if UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiom.pad {
UIDevice.current.setValue(NSNumber(value: UIDeviceOrientation.unknown.rawValue), forKey: "orientation")
UIDevice.current.setValue(NSNumber(value: UIDeviceOrientation.portrait.rawValue), forKey: "orientation")
UIApplication.shared.setStatusBarOrientation(.portrait, animated: false)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
canAutorotate = false
}
override var shouldAutorotate: Bool {
return canAutorotate
}
override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
if UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiom.pad {
return .portrait
}
return .all
}
override var preferredInterfaceOrientationForPresentation : UIInterfaceOrientation {
if UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiom.pad {
return .portrait
}
return .portraitUpsideDown
}
- 帐号密码登录:
LaDateTool.shared.laDateString :网络拉取的时间 --- 系统的时间可能被修改
authkey 计算公式: sha1( "(username)_sha1(password)IOS(MMddyy)")
//114啦帐号密码登录
class func loginWith114Account(_ account: String, _ password: String) {
if reachability?.isReachable() == false {
MBProgressHUD.showFailImage("网络异常,请检查网络连接")
return
}
MBProgressHUD.showGIFView(HUDWaitingAnimationView.shared.startAnimation(), text: "正在登录")
let sha1Pwd = password.sha1Hash ?? ""
var params = [String:Any]()
params["username"] = account
params["pwd"] = sha1Pwd
params["appkey"] = "f7a30e1a01944368e0e4"
params["type"] = "browser"
params["authkey"] = "\(account)_\(sha1Pwd)_IOS_\(LaDateTool.shared.laDateString)".sha1Hash ?? ""
params["app"] = 1
let paramString = params.buildStringFromDictionary().addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) ?? params.buildStringFromDictionary()
guard let url = URL(string: YYWApiCenter.get114AccountLoginApi() + "?" + paramString) else { return }
let requset = URLRequest(url: url, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 30.0)
let urlSession = URLSession(configuration: URLSessionConfiguration.default)
let task = urlSession.dataTask(with: requset) { (data, respone, error) in
DispatchQueue.main.async {
if let data = data {
let json = JSON.init(data: data)
HUDWaitingAnimationView.shared.stopAnimation()
if json["status"].intValue == 1 {
//成功登录就记录下用户帐号及头像
let user = User(laDict: json["data"].rawDictionary)
UserCenter.shared().user = user
let loginDic:[String:String] = ["user_account": account, "user_logo": json["data"]["face"].rawString, "user_id": user.laUserID, "user_pwd": password.sha1Hash ?? ""]
UserDefaults.standard.set(json["data"].rawDictionary, forKey: "defaults_114laUser_authdata")
UserDefaults.standard.set(loginDic, forKey: "last_114laUser_info")
MBProgressHUD.show(kMBProgressHUDImageSuccess, text: "登录成功")
NotificationCenter.default.post(name: Notification.Name(rawValue: "login114Completed"), object: nil)
guard let navigationController = UIApplication.shared.delegate?.window??.rootViewController as? UINavigationController else { return }
for (index,vc) in navigationController.viewControllers.enumerated() {
if vc is NewAuthViewController {
let popVc = navigationController.viewControllers[index-1]
navigationController.popToViewController(popVc, animated: true)
return
}
}
if let nav = navigationController.presentedViewController as? UINavigationController {//可能在说明书多级分类界面中进入,要这样退出该界面。
for (index,vc) in nav.viewControllers.enumerated() {
if vc is NewAuthViewController {
let popVc = nav.viewControllers[index-1]
nav.popToViewController(popVc, animated: true)
return
}
}
}
// loginService.bind115MsgLogin(json["data"]["token"].rawString)
} else {
var error_msg = "帐号或密码错误"
if json["info"].stringValue != "参数错误" {
error_msg = json["info"].stringValue
}
MBProgressHUD.showFailImage(error_msg)
}
} else {
HUDWaitingAnimationView.shared.stopAnimation()
MBProgressHUD.showFailImage("网络异常,请检查网络连接")
}
}
}
task.resume()
}
- 授权登录:
授权登录是根据以下方法生成nonce传给115或115+。
func gotoAuthToOOF(_ strApp: String) {
let timeStamp = String(format: "%.f", Date().timeIntervalSince1970)
let arcMd5 = String(format: "%.f", arc4random()).md5()
strNonce = "114laver=\(YYWApiCenter.getBrowserVersion())&nonce=\(String(describing: arcMd5))×tamp=\(timeStamp)"
guard let tempStrNonce = CryptHelper.browserAES256Encrypt(strNonce, key: CryptHelper.generateBrowserKey()) else {
print("gotoAuthToOOF:-tempStrNonce=nil")
return
}
let strOOF = "\(strApp)://login.com/auth?nonce=\(String(describing: tempStrNonce))"
AppDelegate.openOOFURL(URL(string: strOOF)!, {_ in
})
}
然后115再请求114啦服务器,有帐号直接返回相互绑定好的帐号114la_token与115帐号的信息
if let strRes = results["res"], url.absoluteString.hasPrefix("oof.browser://login.com/auth") {
if let _ = UserDefaults.standard.object(forKey: "defaults_user_authdata") {
MBProgressHUD.show(kMBProgressHUDImageWarning, text: "已有帐号登录")
return true
}
let strd = strRes.ud_UrlDecoded() as String
let resData = CryptHelper.browserAES256Decrypt(with: CryptHelper.data(withBase64EncodedString: strd), key: CryptHelper.generateAuthClientKey()) ?? Data()
if let strDecode = String(data: resData, encoding: String.Encoding.utf8) {
let result = JSON.parse(string: strDecode)
if result != JSON.null {
if result["state"].boolValue == true {
if let data = result["data"].object as? [String : Any] {
if let token = data["114la_token"] as? String {
loginService.authLogin114la(token, offData: data)
return true
}
}
}else{
if let errmsg = result["message"].object as? String {
MBProgressHUD.show(kMBProgressHUDImageFail, text: "登录失败\r\n\(errmsg)")
}
return false
}
}
}
MBProgressHUD.show(kMBProgressHUDImageFail, text: "已取消\r\n解密失败")
return false
}
最后根据115返回的114la_token去获取114啦帐号相关信息。
/*
static let regMobileAppKey = "f7a30e1a01944368e0e4"
115第三方登录
POST 请求
openid true string 115登录返回的唯一串
app true int 客户端类型,ios传1;安卓端传2
appkey true string 固定值;各个频道不一致。
authkey true string app=1时:sha1(openid_IOS_MMDDYY);app=2时:
sha1(openid_ANDROID_MMDDYY);
*/
static func authLogin114la(openid: String, _ handle: @escaping CompletionHandle) -> Void {
let request = YYW114LaRequest()
request.params["openid"] = openid
request.params["app"] = 1
request.params["appkey"] = regMobileAppKey
request.params["authkey"] = "\(openid)_IOS_\(LaDateTool.shared.laDateString)".sha1Hash ?? ""
request.apiURL = "http://my.114la.com/app/open115login"
request.apiResource = ""
request.postAsyncWithCompleteHandle(handle)
}
登录成功后则创建user对象,并缓存用户信息,并发出登录成功的通知。
当需要在登录成功时做事情时可以直接添加通知观察者。
通知名:
"login114Completed" 登录114啦成功
"loginCompleted" 登录115成功
之前有区分两个登录后做的事情,所以分为两个通知发出。
退出登录时会清空缓存。