IOS OAuth授权分析
一、黑马微博 ---> 用户的微博数据
1.成为新浪的开发者(加入新浪微博的开发阵营)
* 注册一个微博帐号,登录http://open.weibo.com
帐号:643055866@qq.com
密码:ios4762450
* 填写开发者的个人信息(比如姓名、出生日期、上传身份证)
2.创建应用
* 假设应用名称叫做“黑马微博”
* 应用创建完毕,默认就进入“开发”阶段,就具备了授权的资格
* 应用相关数据
App Key:3141202626 // 应用的唯一标识
App Secret:ee9de4d2431be061b22fe328332a5228
Redirect URI:http://www.itheima.com
3.用户对“黑马微博”进行资源授权----OAuth授权2.0
1> 获取未授权的Request Token : 展示服务器提供商提供的登录页面
* URL : https://api.weibo.com/oauth2/authorize
* 参数
client_id true string 申请应用时分配的AppKey // 得知道给哪个应用授权
redirect_uri true string 授权回调地址 // 授权成功后跳转到哪个页面
2> 获取授权过的Request Token
* 授权成功后,自动跳转到回调页面,比如
http://www.itheima.com/?code=eabdc03cc4cc51484111b1cfd9c4cd0b
// 新浪会在回调页面后面拼接一个参数:授权成功后的Request Token
3> 根据授权过的Request Token换取一个Access Token
* URL : https://api.weibo.com/oauth2/access_token
* 参数
client_id true string 申请应用时分配的AppKey。
client_secret true string 申请应用时分配的AppSecret。
grant_type true string 请求的类型,填写authorization_code
code true string 调用authorize获得的code值。
redirect_uri true string 回调地址,需需与注册应用里的回调地址一致
* 返回结果
{
"access_token" = "2.00vWf4GEUSKa7D739148f7608SXA9B";
"expires_in" = 157679999;
"remind_in" = 157679999;
uid = 3758830533;
}
// uid == user_id == 当前登录用户的ID == 用户的唯一标识
{
"access_token" = "2.00vWf4GEUSKa7D739148f7608SXA9B";
"expires_in" = 157679999;
"remind_in" = 157679999;
uid = 3758830533;
}
* access_token和uid的去呗
access_token : 1个用户给1个应用授权成功后,就获得对应的1个access_token,作用是:允许1个应用访问1个用户的数据
uid:1个用户对应1个uid,每1个用户都有自己唯一的uid
举例:
张三
李四
应用1
应用2
张三给应用1、应用2授权成功了:1个uid、2个access_token
李四给应用2授权成功了:1个uid、1个access_token
上面操作:产生了2个uid,3个access_token
二、授权过程中常见错误:
1.invalid_request
1> 没有传递必填的请求参数
2> 请求参数不对
3> URL中间留有空格
2.invalid_client
1> client_id的值传递错误(AppKey不对)
3.redirect_uri_mismatch
1> 回调地址不对
三、授权帐号注意
1.如果应用还没有经过新浪审核,只能访问自己或者其他15个测试帐号的微博数据
授权code (HMOAuthViewController.m)
#import "HMOAuthViewController.h" #import "MBProgressHUD+MJ.h" #import "AFNetworking.h" #import "HMTabBarViewController.h" #import "HMNewfeatureViewController.h" @interface HMOAuthViewController () <UIWebViewDelegate> @end @implementation HMOAuthViewController - (void)viewDidLoad { [super viewDidLoad]; //1.创建UIWebView UIWebView * webView=[[UIWebView alloc]init]; webView.frame=self.view.frame; [self.view addSubview:webView]; //2.加载登录页面 NSURL *url=[NSURL URLWithString:@"https://api.weibo.com/oauth2/authorize?client_id=881257207&redirect_uri=http://blog.sina.com.cn"]; NSURLRequest *request=[NSURLRequest requestWithURL:url]; [webView loadRequest:request]; //3.设置代理 webView.delegate=self; } #pragma mark - UIWebViewDelegate /** *UIWebView开始加载资源的时候调用(开始发送请求) * */ -(void)webViewDidStartLoad:(UIWebView *)webView { [MBProgressHUD showMessage:@"正在加载中......"]; } /** *UIWebView加载完毕的时候调用(请求完毕) * */ -(void)webViewDidFinishLoad:(UIWebView *)webView { [MBProgressHUD hideHUD]; } /** *UIWebView加载失败的时候调用(请求失败) * */ -(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { [MBProgressHUD hideHUD]; } /** *UIWebView每当发送一个请求之前,都会先调用这个代理方法(询问代理允不允许加载这个请求) * *@param request 即将发送的请求 *@reture Yes 允许加载 NO:禁止加载 */ -(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { //1.获得请求地址 NSString *url=request.URL.absoluteString; //2.判断url是否为回调地址 /** ~~~~ url = http://www.itheima.com/?code=a3db74011c311e629bafce3e50c25339 range.location == 0 range.length > 0 */ /** url = https://api.weibo.com/oauth2/authorize range.location == NSNotFound range.length == 0 */ NSRange range=[url rangeOfString:@"http://blog.sina.com.cn/?code="]; if(range.location!=NSNotFound)//是回调地址 { //截取授权成功后的请求标记 int from=range.location+range.length; NSString *code=[url substringFromIndex:from]; //根据code获得一个accessToken [self accessTokenWithCode:code]; //禁止加载回调页面 return NO; } return YES; } /** *根据code获得一个accessToken * *@param code 授权成功后的请求标记 */ -(void)accessTokenWithCode:(NSString *)code { //1.获得请求管理者 AFHTTPRequestOperationManager *mgr=[AFHTTPRequestOperationManager manager]; //2.封装请求参数 NSMutableDictionary *params=[NSMutableDictionary dictionary]; params[@"client_id"]=@"881257207"; params[@"client_secret"]=@"0b8c34d4659d656834f827abfb3a1805"; params[@"redirect_uri"]=@"http://blog.sina.com.cn"; params[@"grant_type"]=@"authorization_code"; params[@"code"]=code; //3.发送POST请求 [mgr POST:@"https://api.weibo.com/oauth2/access_token" parameters:params success:^(AFHTTPRequestOperation *operation, NSDictionary *responseObject) { //隐藏HUD [MBProgressHUD hideHUD]; HMLog(@"请求成功。。。。。"); //存储授权成功的帐号信息 NSString *doc=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject]; NSString *filepth=[doc stringByAppendingPathComponent:@"account.plist"]; [responseObject writeToFile:filepth atomically:YES]; //切换控制器(可能去新特性\tabBar) //如何知道第一次使用这个版本?比较上次的使用情况 NSString * versionKey=(__bridge NSString*)kCFBundleVersionKey; //从沙盒中取出上次存储的软件版本号(取出用户上次的使用记录) NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults]; NSString *lastVersion=[defaults objectForKey:versionKey]; //获得当前打开软件的版本号 NSString *currentVersion=[NSBundle mainBundle].infoDictionary[versionKey]; UIWindow *window=[UIApplication sharedApplication].keyWindow; if([currentVersion isEqualToString:lastVersion])//当前版本号==上次使用的版本:显示HMTabBarViewController { window.rootViewController=[[HMTabBarViewController alloc]init]; } else{//当前版本号 !=上次使用的版本:显示版本新特性 window.rootViewController=[[HMNewfeatureViewController alloc]init]; //存储这次使用的软件版本 [defaults setObject:currentVersion forKey:versionKey]; [defaults synchronize]; } } failure:^(AFHTTPRequestOperation *operation, NSError *error) { //隐藏HUD [MBProgressHUD hideHUD]; HMLog(@"请求失败--@",error); }]; } /** Request failed: unacceptable content-type: text/plain */ @end
调用code 信息
#import "AppDelegate.h" #import "HMTabBarViewController.h" #import "HMNewfeatureViewController.h" #import "HMOAuthViewController.h" @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { application.statusBarHidden=NO; //1.创建窗口 self.window=[[UIWindow alloc]init]; self.window.frame=[UIScreen mainScreen].bounds; //2.设置窗口的根控制器 NSString *doc=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject]; NSString *filepath=[doc stringByAppendingPathComponent:@"account.plist"]; NSDictionary *account=[NSDictionary dictionaryWithContentsOfFile:filepath]; if(account){ //如果知道第一次使用这个版本?比较上次的使用情况 NSString *versionKey=(__bridge NSString *)kCFBundleVersionKey; //从沙盒中取出上次存储的软件版本号(取出用户上次的使用记录) NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults]; NSString *lastVersion=[defaults objectForKey:versionKey]; //获得当前打开软件的版本号 NSString *currentVersion=[NSBundle mainBundle].infoDictionary[versionKey]; if([currentVersion isEqualToString:lastVersion])// 当前版本号 == 上次使用的版本:显示HMTabBarViewController { self.window.rootViewController=[[HMTabBarViewController alloc]init]; } else// 当前版本号 != 上次使用的版本:显示版本新特性 { self.window.rootViewController= [[HMNewfeatureViewController alloc] init]; //存储这次使用的软件版本 [defaults setObject:currentVersion forKey:versionKey]; [defaults synchronize]; } }else{//没有登录过 self.window.rootViewController=[[HMOAuthViewController alloc]init]; } //3.显示窗口(成为主窗口) [self.window makeKeyAndVisible]; return YES; }