基于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 = "\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写的简直丧心病狂,须要极度耐心才干看明确,表示非常无语,另外本三种方式授权登录的源码有偿提供,如需能够邮件mmw05@163.com联系就可以。
2,嵌入时间
微信算是非常easy嵌入SDK,QQ也还能够。微博须要注意boundID有限制。微信的逻辑算是比較冗余繁琐。从授权到获取到用户信息须要非常多接口,而QQ和微博能够直接从授权登陆回调中获取到。是比較便捷的。从上面代码能够看出来;
后记
从objective-C到Swift,苹果力求简约,但又不简单,现代化的语言,必定在性能各方面优于传统,仅仅是须要时间和很多其它的考验,作为开发人员。多一个选择,岂不更好。
附图:
基于Swift语言开发微信、QQ和微博的SSO授权登录代码分析的更多相关文章
- 微信qq,新浪等第三方授权登录的理解
偶们常说的第三方是指的微信,qq,新浪这些第三方,因为现在基本每个人都有qq或者微信,那么我们就可以通过这些第三方进行登录.而这些网站比如慕课网是通过第三方获取用户的基本信息 它会有个勾选按钮,提示是 ...
- 基于Java语言开发jt808、jt809技术文章精华索引
很多技术开发人员喜欢追逐最新的技术,如Node.js, go等语言,这些语言只是解决了某一个方面,如只是擅长异步高并发等等,却在企业管理后台开发方面提供的支持非常不够,造成项目团队技术选项失败,开发后 ...
- vue+uni-app商城实战 | 第一篇:【有来小店】微信小程序快速开发接入Spring Cloud OAuth2认证中心完成授权登录
一. 前言 本篇通过实战来讲述如何使用uni-app快速进行商城微信小程序的开发以及小程序如何接入后台Spring Cloud微服务. 有来商城 youlai-mall 项目是一套全栈商城系统,技术栈 ...
- 使用Java语言开发微信公众平台(三)——被关注回复与关键词回复
在上一篇文章中,我们实现了文本消息的接收与响应.可以在用户发送任何内容的时候,回复一段固定的文字.本章节中,我们将对上一章节的代码进行适当的完善,同时实现[被关注回复与关键词回复]功能. 一.微信可提 ...
- 使用Java语言开发微信公众平台(五)——被关注回复与关键词回复
在上一篇文章中,我们实现了文本消息的接收与响应.可以在用户发送任何内容的时候,回复一段固定的文字.本章节中,我们将对上一章节的代码进行适当的完善,同时实现[被关注回复与关键词回复]功能. 一.微信 ...
- C#-MVC开发微信应用(2)--OAuth2.0网页授权
微信公众平台最近新推出微信认证,认证后可以获得高级接口权限,其中一个是OAuth2.0网页授权,很多朋友在使用这个的时候失败了或者无法理解其内容,希望我出个教程详细讲解一下,于是便有了这篇文章. 一. ...
- 微信订阅号里实现oauth授权登录,并获取用户信息 (完整篇)
摘要 这段时间一直有人问我,订阅号实现的oauth授权登录的问题,之前写的比较简单,很多人不明白.众所周知,微信公众号分订阅号.服务号.企业号:每个号的用途不一样,接口开放程度也不一样.微信还有个扯淡 ...
- PHP微信公众平台oauth2.0网页授权登录类的封装demo
一.微信授权使用的是OAuth2.0授权的方式.主要有以下简略步骤: 第一步:用户同意授权,获取code 第二步:通过code换取网页授权access_token 第三步:拉取用户信息(需scope为 ...
- 微信公众号抢现金红包活动的核心代码分析(asp.net C#)
今年春节微信抢红包,我想各位都还记得.最近很多商家也在使用公众号给粉丝发红包,做营销活动.吸粉活动或者是反馈老用户等. 我们作为第3方开发者,就义不容辞的来给这些商家服务了.首先我们得会使用程序来写抢 ...
随机推荐
- python模块之HTMLParser(原理很大程度上就是对类构造的熟练运用)
# -*- coding: utf-8 -*- #python 27 #xiaodeng #python模块之HTMLParser(原理很大程度上就是对类构造的熟练运用) import HTMLPar ...
- ArcGIS调整影像颜色输出
有碰到一些质量很差的遥感影像,颜色需要进行调整(主要是针对看)输出,这里记录一下ArcGIS中的调整输出方式. 1.首先把影像文件拖入ArcMap中,然后右键单击图层列表中的图像,选择属性. 2.选择 ...
- svn备份与还原_脚本_(dump命令)
今天备份svn, 能保证好用就行先, 回头再研究 buerguo.bat @echo off :: 关闭回显 :: 说明:如有命令不明白,请使用帮助命令:命令/? .如:for/? :: 设置标题 t ...
- LATeX 插入脚注
LATeX 插入脚注: 使用 \footnote{...注释内容} 命令: To maximize the lower-bound $ we employ conjugate gradient me ...
- HDU 2492 Ping pong (数状数组)
Ping pong Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total S ...
- SpringBoot配置属性转载地址
SpringBoot配置属性系列 SpringBoot配置属性之MVC SpringBoot配置属性之Server SpringBoot配置属性之DataSource SpringBoot配置属性之N ...
- 【struts2】Struts2的系统架构
Struts2的官方文档里附带了Struts2的架构图,下面这张图上展示了Struts2的内部模块,以及它们的运行流程. 这张图上分了好多块,彼此之间相互联系,先浏览一下各块的名字,再留心一下运行图最 ...
- 【Linux】字符转换命令paste
这个 paste 就要比join 简单多了!相对于 join 必须要比对两个文件的数据相关性, paste 就直接『将两行贴在一起,且中间以 [tab] 键隔开』而已!简单的使用方法: [root@w ...
- SQL如何获得本季度第一天、一年的第一天、本月的最后一天
nterval 参数,具有以下设定值: 设置 描述 Year yy, yyyy 年 quarter qq, q 季 Month mm, m 月 dayofyear dy, y 一年的日数 Day dd ...
- C/C++/动态链接库DLL中函数的调用约定与名称修饰
参见:http://blog.twofei.com/cc/impl/calling-convension.html 调用约定(Calling Convention)是指在程序设计语言中为了实现函数调用 ...