zoukankan      html  css  js  c++  java
  • 基于Swift语言开发微信、QQ和微博的SSO授权登录代码分析

    前言

    Swift 语言,怎么说呢,有一种先接受后排斥。又欢迎的感觉,纵观国外大牛开源框架或项目演示,Swift差点儿占领了多半,而国内尽管出现非常多相关技术介绍和教程,可是在真正项目开发中使用的占领非常少部分。原因一是眼下熟练它的开发人员并不多,二是版本号不太稳定,还须要更成熟可靠的版本号支持,但总之未来还是非常有前景的。深有体会。无论是代码量还是编译效率。以及语言特性。现代性都优于Object-C,预计兴许会被苹果作为官方开发语言,值得期待。


    走起

    鉴于此,笔者将之前用Object-C写的SSO授权登录:微信,QQ和微博。又一次用Swift语言写一遍,以便须要的朋友參考。算是SSO授权登录的姊妹篇;


    一,整体架构

    1,引入第三方库

    除了必须引入相应的登录SDK外,额外引入了SDWebImage。SVProgressHUD。看名字大家都明确吧。引入登录SDK请各自看官方的开发文档,须要增加什么系统库文件。须要配置Other Linker Flags 等,请參考各自官方文档就可以。

    2,配置连接桥文件

    由于创建的project是基于Swift语言,眼下官方SDK和其他三方库都是用OC写的,所以为了在swift中调用oc代码。须要配置连接桥文件Bridging-Header.h,搜索objective-C bridging Header健,然后在值里面输入XXXLogin/Bridging-Header.h,注意是绝对路径。里面能够输入须要调用的头文件。如

    #import "WXApi.h"
    #import "SVProgressHUD.h"
    #import "UIImageView+WebCache.h"


    3,配置project

    由于是SSO跳转方式,须要配置URL Schemes,以便程序返回识别宿主程序。配置方法非常easy,參考各自文档就可以。在info里面能够可视化加入。各自的key值採用官方demo所提供。

    二,微信

    1。注冊
    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
            // Override point for customization after application launch.
            
            //向微信注冊
            WXApi.registerApp(kWXAPP_ID)
            
            return true
        }

    2,授权登录
    override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view, typically from a nib.
            
            NSNotificationCenter.defaultCenter().addObserver(self, selector:"onRecviceWX_CODE_Notification:", name: "WX_CODE", object: nil)
            
            
            let sendBtn:UIButton = UIButton()
            sendBtn.frame = CGRectMake(30, 100, kIPHONE_WIDTH-60, 40)
            sendBtn.backgroundColor = UIColor.redColor()
            sendBtn.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
            sendBtn.setTitle("Swift版本号之微信授权登录", forState: UIControlState.Normal)
            sendBtn.addTarget(self, action: "sendBtnClick:", forControlEvents: UIControlEvents.TouchUpInside)
            self.view.addSubview(sendBtn)
            
            
            headerImg = UIImageView(frame: CGRectMake(30, 160, 120, 120))
            headerImg.backgroundColor = UIColor.yellowColor()
            self.view.addSubview(headerImg)
            
            nicknameLbl.frame = CGRectMake(170, 160, kIPHONE_WIDTH-60-140, 40)
            nicknameLbl.backgroundColor = UIColor.lightGrayColor()
            nicknameLbl.textColor = UIColor.purpleColor()
            nicknameLbl.textAlignment = NSTextAlignment.Center
            self.view.addSubview(nicknameLbl)
            
        }
        
        
        func sendBtnClick(sneder:UIButton)
        {
            sendWXAuthRequest()
        }
        
        //微信登录 第一步
        func sendWXAuthRequest(){
            
            let req : SendAuthReq = SendAuthReq()
            req.scope = "snsapi_userinfo,snsapi_base"
            WXApi .sendReq(req)
        }

    3,回调
     func onResp(resp: BaseResp!) {
            
            /*
            
            ErrCode	ERR_OK = 0(用户允许)
            ERR_AUTH_DENIED = -4(用户拒绝授权)
            ERR_USER_CANCEL = -2(用户取消)
            code	用户换取access_token的code,仅在ErrCode为0时有效
            state	第三方程序发送时用来标识其请求的唯一性的标志,由第三方程序调用sendReq时传入。由微信终端回传。state字符串长度不能超过1K
            lang	微信client当前语言
            country	微信用户当前国家信息
            */
            // var aresp resp :SendAuthResp!
            var aresp = resp as! SendAuthResp
            //  var aresp1 = resp as? SendAuthResp
            
            if (aresp.errCode == 0)
            {
                println(aresp.code)
                //031076fd11ebfa5d32adf46b37c75aax
                
                var dic:Dictionary<String,String>=["code":aresp.code];
                let value = dic["code"]
                println("code:(value)")
                
                NSNotificationCenter.defaultCenter().postNotificationName("WX_CODE", object: nil, userInfo: dic)
                
            }
        }
    

    4,获取用户信息

    //微信回调通知,获取code 第二步
        
        func onRecviceWX_CODE_Notification(notification:NSNotification)
        {
            SVProgressHUD.showSuccessWithStatus("获取到code", duration: 1)
            
            var userinfoDic : Dictionary = notification.userInfo!
            let code: String = userinfoDic["code"] as! String
            
            println("Recevice Code: (code)")
            
            self.getAccess_token(code)
        }
        
        //获取token 第三步
        func getAccess_token(code :String){
            //https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
            
            var requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?

    appid=(kWXAPP_ID)&secret=(kWXAPP_SECRET)&code=(code)&grant_type=authorization_code" dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { var requestURL: NSURL = NSURL(string: requestUrl)! var data = NSData(contentsOfURL: requestURL, options: NSDataReadingOptions(), error: nil) dispatch_async(dispatch_get_main_queue(), { var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: nil) as! NSDictionary println("Recevice Token: (jsonResult)") SVProgressHUD.showSuccessWithStatus("获取到Token和openid", duration: 1) let token: String = jsonResult["access_token"] as! String let openid: String = jsonResult["openid"] as! String self.getUserInfo(token, openid: openid) }) }) } //获取用户信息 第四步 func getUserInfo(token :String,openid:String){ // https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID var requestUrl = "https://api.weixin.qq.com/sns/userinfo?

    access_token=(token)&openid=(openid)" dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { var requestURL: NSURL = NSURL(string: requestUrl)! var data = NSData(contentsOfURL: requestURL, options: NSDataReadingOptions(), error: nil) dispatch_async(dispatch_get_main_queue(), { var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: nil) as! NSDictionary println("Recevice UserInfo: (jsonResult)") /* Recevice UserInfo: { city = Chaoyang; country = CN; headimgurl = "http://wx.qlogo.cn/mmopen/FrdAUicrPIibcpGzxuD0kjfssQogj3icL8QTJQYUCLpgzSnvY6rJFGORreicPUiaPCzojwNlsXq4ibbc8e3gGFricWqJU5ia7ibicLVhfT/0"; language = "zh_CN"; nickname = "U706bU9505U6599"; openid = "oyAaTjkR8T6kcKWyA4VPYDa_Wy_w"; privilege = ( ); province = Beijing; sex = 1; unionid = "o1A_Bjg52MglJiEjhLmB8SyYfZIY"; } */ SVProgressHUD.showSuccessWithStatus("获取到用户信息", duration: 1) let headimgurl: String = jsonResult["headimgurl"] as! String let nickname: String = jsonResult["nickname"] as! String self.headerImg.sd_setImageWithURL(NSURL(string: headimgurl)) self.nicknameLbl.text = nickname }) }) }



    5,跳转

     //微信的跳转回调
        func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject?) -> Bool    {
            return  WXApi.handleOpenURL(url, delegate: self)
        }
      func application(application: UIApplication, handleOpenURL url: NSURL) -> Bool 
    <span style="white-space:pre">	</span>{
            return  WXApi.handleOpenURL(url, delegate: self)
        }
        

    三。QQ

    1,注冊
        func sendBtnClick(sneder:UIButton)
        {
            sendQQAuthRequest()
        }
        
        //第一步  QQ登录
        func sendQQAuthRequest(){
            
            tencentOAuth = TencentOAuth(appId: kQQAPP_ID, andDelegate: self)
            var permissions = [kOPEN_PERMISSION_GET_INFO,kOPEN_PERMISSION_GET_USER_INFO,kOPEN_PERMISSION_GET_SIMPLE_USER_INFO]
            tencentOAuth.authorize(permissions, inSafari: false)
            
        }
    


    2,授权登录

    如上

    3。回调

     //第二步 登录成功回调
        func tencentDidLogin() {
            let accessToken = tencentOAuth.accessToken
    
            println("accessToken:(accessToken)") //641B23508B62392C52D6DFADF67FAA9C
    
            getUserInfo()
        }
        
        //失败
        func tencentDidNotLogin(cancelled: Bool) {
            println("登录失败了")
        }
        
        //无网络
        func tencentDidNotNetWork() {
            println("没有网络")
        }
        

    4。获取用户信息

     //第三步 获取用户信息
        func getUserInfo()
        {
            SVProgressHUD.showWithStatus("正在获取用户信息...")
    
            tencentOAuth.getUserInfo()
        }
        
        
        //第四步 在获取用户回调中获取用户信息
        func getUserInfoResponse(response: APIResponse!) {
            
            SVProgressHUD.dismissWithSuccess("获取用户信息成功", afterDelay: 1)
    
            var dic:Dictionary = response.jsonResponse
            
            println("dic:(dic)")
            
            //        [is_lost: 0, figureurl: http://qzapp.qlogo.cn/qzapp/222222/C5527A2F775D9EA7C20317128FAC202B/30, vip: 0, is_yellow_year_vip: 0, province: 北京, ret: 0, is_yellow_vip: 0, figureurl_qq_1: http://q.qlogo.cn/qqapp/222222/C5527A2F775D9EA7C20317128FAC202B/40, yellow_vip_level: 0, level: 0, figureurl_1: http://qzapp.qlogo.cn/qzapp/222222/C5527A2F775D9EA7C20317128FAC202B/50, city: 海淀, figureurl_2: http://qzapp.qlogo.cn/qzapp/222222/C5527A2F775D9EA7C20317128FAC202B/100, nickname: 竹中雨滴, msg: , gender: 男, figureurl_qq_2: http://q.qlogo.cn/qqapp/222222/C5527A2F775D9EA7C20317128FAC202B/100]
            
            
            refeshUserInfo(dic)
        }
        
        
        //第五步 刷新用户界面
        func refeshUserInfo(dic : NSDictionary){
        
            let headimgurl: String = dic["figureurl_qq_2"] as! String
            let nickname: String = dic["nickname"] as! String
            
            self.headerImg.sd_setImageWithURL(NSURL(string: headimgurl))
            self.nicknameLbl.text = nickname
    
        }
    
    5。跳转

      func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject?

    ) -> Bool { return TencentOAuth.HandleOpenURL(url) } func application(application: UIApplication, handleOpenURL url: NSURL) -> Bool { return TencentOAuth.HandleOpenURL(url) }




    四,微博

    1。注冊

     func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
            // Override point for customization after application launch.
            
            WeiboSDK.registerApp(kAppKey)
            
            return true
        }

    2。授权登录

    func sendBtnClick(sneder:UIButton)
        {
            sendSinaAuthRequest()
        }
        
        //第一步  微博登录
        func sendSinaAuthRequest(){
            
            var request : WBAuthorizeRequest = WBAuthorizeRequest.request() as! WBAuthorizeRequest
            request.redirectURI = kRedirectURI
            request.scope = "all"
            request.userInfo = ["SSO_Key":"SSO_Value"]
            WeiboSDK.sendRequest(request)
        }

    3。回调

    func didReceiveWeiboRequest(request: WBBaseRequest!) {
    
        }
        
        func didReceiveWeiboResponse(response: WBBaseResponse!) {
      
            if response.isKindOfClass(WBAuthorizeResponse){
    
                if (response.statusCode == WeiboSDKResponseStatusCode.Success) {
                
                    var authorizeResponse : WBAuthorizeResponse = response as! WBAuthorizeResponse
                    var userID = authorizeResponse.userID
                    var accessToken = authorizeResponse.accessToken
                    
                    println("userID:(userID)
    accessToken:(accessToken)")
                    
                    var userInfo = response.userInfo as Dictionary
                    
                    NSNotificationCenter.defaultCenter().postNotificationName("SINA_CODE", object: nil, userInfo: userInfo)
    
                }
            }
        }

    4。获取用户信息

    //第二步  通过通知得到登录后获取的用户信息
        func onRecviceSINA_CODE_Notification(notification:NSNotification)
        {
            SVProgressHUD.showSuccessWithStatus("获取到用户信息", duration: 1)
            
            var userinfoDic : Dictionary = notification.userInfo!
            
            println("userInfo:(userinfoDic)")
            
            
            /*
            userID:2627289515
            accessToken:2.002BqnrCyY87OC80500cab28Ofqd3B
            userInfo:
            [uid: 2627289515, remind_in: 647057, scope: invitation_write, refresh_token: 2.002BqnrCyY87OC10f7877765yPietB,
            app: {
            logo = "http://ww1.sinaimg.cn/square/65745bf7jw1ea399us692j2028028glf.jpg";
            name = "SDKU5faeU535aU5e94U7528demo";
            }, 
            access_token: 2.002BqnrCyY87OC80500cab28Ofqd3B, expires_in: 647057
            ]
            
            */
            
            var userAppInfo: Dictionary<String,String> = userinfoDic["app"] as! Dictionary
            
            refeshUserInfo(userAppInfo)
        }
    
        //第三步 刷新用户界面
        func refeshUserInfo(dic : NSDictionary){
            
            let headimgurl: String = dic["logo"] as! String
            let nickname: String = dic["name"] as! String
            
            self.headerImg.sd_setImageWithURL(NSURL(string: headimgurl))
            self.nicknameLbl.text = nickname
        }
    


    5,跳转
    func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject?

    ) -> Bool { return WeiboSDK.handleOpenURL(url, delegate: self) } func application(application: UIApplication, handleOpenURL url: NSURL) -> Bool { return WeiboSDK.handleOpenURL(url, delegate: self) }


    五,对照分析

    1。demo情况

    微博demo代码工整度完爆微信。QQ。看着非常舒服,心情也不错。另外微博放在了github上面。适合pod管理。凝视也极好,微信文档写的挺不错,QQ写的简直丧心病狂,须要极度耐心才干看明确,表示非常无语,另外本三种方式授权登录的源码有偿提供,如需能够邮件mmw05@163.com联系就可以。

    2,嵌入时间

    微信算是非常easy嵌入SDK,QQ也还能够。微博须要注意boundID有限制。微信的逻辑算是比較冗余繁琐。从授权到获取到用户信息须要非常多接口,而QQ和微博能够直接从授权登陆回调中获取到。是比較便捷的。从上面代码能够看出来;

    后记

    从objective-C到Swift,苹果力求简约,但又不简单,现代化的语言,必定在性能各方面优于传统,仅仅是须要时间和很多其它的考验,作为开发人员。多一个选择,岂不更好。


    附图:

  • 相关阅读:
    字节跳动在 Go 网络库上的实践
    TCP报文段的首部格式 20字节的固定首部
    网易公开课 文件描述符 索引
    网易新闻App架构重构实践:DDD正走向流行
    货 | 携程是如何做AB实验分流的
    Pusher Channels Protocol | Pusher docs https://pusher.com/docs/channels/library_auth_reference/pusher-websockets-protocol
    避免重复提交?分布式服务的幂等性设计! 架构文摘 今天 点击蓝色“架构文摘”关注我哟 加个“星标”,每天上午 09:25,干货推送! 来源:https://www.cnblogs.com/QG-whz/p/10372458.html 作者:melonstreet
    前置时间(Lead Time),也称前置期、备货周期
    滴滴业务研发的精益实践
    DevOps运动的缘起 将DevOps想象为一种编程语言里面的一个接口,而SRE类实现了这个接口
  • 原文地址:https://www.cnblogs.com/slgkaifa/p/7355896.html
Copyright © 2011-2022 走看看