基于Swift语言开发微信、QQ和微博的SSO授权登录代码分析

前言

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

走起

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

一,总体架构

1,引入第三方库

除了必须引入对应的登录SDK外,额外引入了SDWebImage,SVProgressHUD,看名字大家都明白吧,引入登录SDK请各自看官方的开发文档,需要加入什么系统库文件,需要配置Other Linker Flags 等,请参考各自官方文档即可;

2,配置连接桥文件

因为创建的工程是基于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,配置工程

因为是SSO跳转方式,需要配置URL Schemes,以便程序返回识别宿主程序,配置方法很简单,参考各自文档即可,在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	微信客户端当前语言
        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 = "\U706b\U9505\U6599";
                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)\naccessToken:\(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 = "SDK\U5fae\U535a\U5e94\U7528demo";
        },
        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写的简直丧心病狂,需要极度耐心才能看明白,表示很无语,另外本三种方式授权登录的源代码有偿提供,如需可以邮件[email protected]即可;

2,嵌入时间

微信算是很容易嵌入SDK,QQ也还可以,微博需要注意boundID有限制,微信的逻辑算是比较冗余繁琐,从授权到获取到用户信息需要很多接口,而QQ和微博可以直接从授权登陆回调中获取到,是比较便捷的,从上面代码可以看出来;

后记

从objective-C到Swift,苹果力求简约,但又不简单,现代化的语言,必然在性能各方面优于传统,只是需要时间和更多的考验,作为开发者,多一个选择,岂不更好!

附图:

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-12 16:08:18

基于Swift语言开发微信、QQ和微博的SSO授权登录代码分析的相关文章

微信qq,新浪等第三方授权登录的理解

偶们常说的第三方是指的微信,qq,新浪这些第三方,因为现在基本每个人都有qq或者微信,那么我们就可以通过这些第三方进行登录.而这些网站比如慕课网是通过第三方获取用户的基本信息 它会有个勾选按钮,提示是否提供一些信息. 但是一些网站还是提示需要输入邮箱和密码,但是如果这些我是在微信的客户端观看这些网站的话,就是通过慕课网的微信公众号来观看的话,就可以获取微信用户与慕课网公众号唯一的 openid就可以唯一的识别用户,openid是通过一个微信号+微信用户通过一个算法来生成的.

基于swift语言iOS8的蓝牙连接(初步)

看过一些蓝牙App的事例,大体上对蓝牙的连接过程进行了了解.但是开始真正自己写一个小的BLE程序的时候就举步维艰了.那些模棱两可的概念在头脑中瞬间就蒸发了,所以还是决定从最基本的蓝牙连接过程进行.这里所说的蓝牙是针对 bluetooth 4.0的. 第一步就是去看官方的关于蓝牙框架的文档,即Core Bluetooth Programming Guide,在苹果的官方网站上可以轻松找到,不管你对蓝牙的基本概念是否有了解,这个文件可以使你更好的对蓝牙的连接过程有个了解.这个文档的前面几张介绍了关于

使用Java语言开发微信公众平台(三)——被关注回复与关键词回复

在上一篇文章中,我们实现了文本消息的接收与响应.可以在用户发送任何内容的时候,回复一段固定的文字.本章节中,我们将对上一章节的代码进行适当的完善,同时实现[被关注回复与关键词回复]功能. 一.微信可提供的消息类型 在上一篇文章中,在我们的Servalet中,我们有这样的一段代码: 我们说这是用于判断接收的消息类型是否为text,即是否为文本消息时,将用户发送的给信息拼接后返回.但这个这个功能现在不足以满足我们的时候,我们将重写代码,实现被关注时自动回复,以及根据关键词自动回复.而首先,我们需要了

微信订阅号里实现oauth授权登录,并获取用户信息 (完整篇)

摘要 这段时间一直有人问我,订阅号实现的oauth授权登录的问题,之前写的比较简单,很多人不明白.众所周知,微信公众号分订阅号.服务号.企业号:每个号的用途不一样,接口开放程度也不一样.微信还有个扯淡的开放平台,号称统一管理众多公众号的.反正都是交钱的功能多,两个平台把我弄得傻傻分不清楚.切入正题,上个公司有个微信订阅号,内嵌了一个微网站,并且要实现授权登录. oauth 授权登录 前段时间一直有人问我有关订阅号实现的oauth授权登录的问题,之前一篇写的比较简单,很多人不明白. 众所周知,微信

如何在微信订阅号里实现oauth授权登录

前端时间折腾过的蛋疼问题,好不容易解决了,现在把这个分享出去: 众所周知,微信公众号分订阅号.服务号.企业号:每个号的用途不一样,接口开放程度也不一样. 微信还有个扯淡的开放平台,号称统一管理众多公众号的.反正都是交钱的功能多,两个平台把我弄得傻傻分不清楚. 切入正题,上个公司有个微信订阅号,内嵌了一个微网站,并且要实现授权登录. 这个授权登录的接口只有认证的服务号才能调用,订阅号要实现这个功能只能另辟蹊径: 这个是微信公众号的api地址 http://mp.weixin.qq.com/wiki

微信公众号抢现金红包活动的核心代码分析

红包使用说明及规则,请仔细阅读 (1)必须是认证过的服务号,开通了微信支付功能:在商家后台充足够多的钱来发红包. (2)发送频率规则◆ 每分钟发送红包数量不得超过1800个:◆ 北京时间0:00-8:00不触发红包赠送:(如果以上规则不满足您的需求,请发邮件至[email protected]获取升级指引) (3)红包规则◆ 单个红包金额介于[1.00元,200.00元]之间:◆ 同一个红包只能发送给一个用户:(如果以上规则不满足您的需求,请发邮件至[email protected]获取升级指引

swift语言开发的一个游戏------熊猫跑酷(KongfuPanda)

项目地址:https://github.com/jakciehoo/KongfuPanda 欢迎加QQ群:260558552.大家一起交流iOS开发,我们可以一起学习,我很想集结一些志同道合的朋友,一起把iOS开发学好,学精,相互学习相互鼓励. 1.首先创建一个游戏项目: 2.将图片资源导入 将我项目里的 atlas整个目录 sound组里的音乐(background.mp3,fly.mp3,hit_platform.mp3,apple.mp3,hit.mp3,jump_from_platfor

使用Java语言开发微信公众平台(七)——音乐消息的回复

在上一节课程中,我们学习了图片消息的回复功能.根据微信公众平台的消息类型显示,微信共支持文本.图片.语音.视频.音乐.图文等6种消息类型的回复: 其中,我们已经实现了文本.图文.图片等消息的回复处理,而语音.视频两种消息类型的功能与图片消息完全一样.均需使用我们写好的文件上传接口,上传文件并获得MediaID,从而使用MediaID推送图片.语音.视频.没有学习过的同学,可进入杰瑞教育博客园继续学习:http://www.cnblogs.com/jerehedu/p/6781456.html 今

PHP语言开发微信公众平台(订阅号)之curl命令

在开发过程中,经常会遇到要求用curl命令调用接口的情况 那么,什么是curl,简单来说curl是一个利用url语法规定来传输文件和哦数据的工具,支持很多协议,如 http.ftp.telent 等,所幸php 也支持 curl curl虽然很复杂,但是很可以总结为四步. curl操作四步走: 1.初始化 $ch = curl_init()2.设置参数 curl_setopt($ch,参数)3.执行 curl_exec($ch)4.关闭 curl_close($ch)输出错误信息: curl_e