IOS博客項目搭建-09-OAuth02受權

抓取數據,須要經過網站的受權web

1、註冊獲取sina受權權限

https://api.weibo.com/oauth2/authorize?client_id=2699927613&redirect_uri=http://digtime.cn json

該連接受權後返回一個code,而後獲取信息api


2、建立權限的控制器、模型、view模塊

 

#import "IWOAuthViewController.h"
#import "AFNetworking.h"
#import "IWAccount.h"
#import "IWTabBarViewController.h"
#import "IWNewfeatureViewController.h"

@interface IWOAuthViewController () <UIWebViewDelegate>

@end

@implementation IWOAuthViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // 1.添加webView
    UIWebView *webView = [[UIWebView alloc] init];
    webView.frame = self.view.bounds;
    [self.view addSubview:webView];
    
    // 2.加載受權頁面(新浪提供的登錄頁面)
    NSURL *url = [NSURL URLWithString:@"https://api.weibo.com/oauth2/authorize?client_id=2699927613&redirect_uri=http://digtime.cn"];   // 訪問的URL
    NSURLRequest *request = [NSURLRequest requestWithURL:url]; // 請求該URL
    [webView loadRequest:request];
    
   }


3、攔截webView的全部請求

經過新浪受權後,頁面會直接跳轉到重定向的地址,可是這裏但願受權後,獲取code碼,拿到Token,而後獲取到用戶的數據,而不是直接跳轉到重定向的地址,因此,這裏須要監聽webView的加載,因此,須要攔截webView的全部請求,解決方法,能夠經過添加代理<UIWebViewDelegate>,而後攔截數據。服務器

 攔截webView自動請求http://digtime.cn/?code=8b1c66a777fe49b26fd650a4f2dacd98的路徑,而後截取code碼,app

 經過code碼獲取accessToken。框架

#pragma mark - webView代理方法
/**
 *  當webView發送一個請求以前都會先調用這個方法, 詢問代理可不能夠加載這個頁面(請求)
 *
 *  @param request
 *
 *  @return YES : 能夠加載頁面,  NO : 不能夠加載頁面
 */
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    // 1.請求的URL路徑
    NSString *urlStr = request.URL.absoluteString;
    
    // 2.判斷字符串裏邊含有'code='字符,目的是攔截該連接,不讓其自動加載,並獲取code碼
    // http://digtime.cn/?code=8b1c66a777fe49b26fd650a4f2dacd98
     NSRange range = [urlStr rangeOfString:@"code="];
    
    // 3.若是urlStr中包含了code=
    //  if(range.location != NSNotFound)
    if(range.length)
    {
        // 4.獲取code=後面的請求標記(通過用戶受權成功的)
        int loc = range.location + range.length;
        NSString *code = [urlStr substringFromIndex:loc];
        
        // 5.發送POST請求給新浪,經過code換取一個accessToken
        // 發送請求通常用別人封裝好的請求框架
        // ASI:HTTP終結者,已經被淘汰
        // AFN(AFNetworking)\AFN
       
        [self accessTokenWithCode:code];
        
    }
    
    NSLog(@"%@", request.URL);
    
    return YES;
    
}


4、經過AFN(AFNetworking)框架發送POST請求,獲取accessToken

具體步驟:網站

1.建立請求管理對象ui

2.封裝請求參數(參數用字典封裝atom

3.發送請求,請求成功後服務器端響應一個對象responseObjecturl

4.先將字典轉爲模型(建立model,IWAccount.h 取數據放數據很是方便)

5.存儲模型數據---存儲accessToken信息 ---歸檔

   5.1獲取沙盒路徑

    5.2 拼接文件路徑

    5.3 Account.h 須要遵照 NSCoding協議,哪些屬性須要歸檔,哪些須要解檔

    5.4 而後須要在IWAppDelegate.m中當應用加載完後,須要判斷用戶之前是否有登錄成功過,沙盒裏邊有數據,而後判斷沙盒數據受權信息是否有過時,若是沒有過時則直接進入微博。

注意:IOS會將服務器返回的json解析成字典


  經過code換取一個accessToken方法:

//  IWOAuthViewController.m

/**
 *  經過code換取一個accessToken
 redirect_uri	true	string	回調地址,需需與註冊應用裏的回調地址一致。
 */
-(void)accessTokenWithCode:(NSString *)code
{
    // 發送POST請求給新浪,經過code換取一個accessToken
    // 發送請求通常用別人封裝好的請求框架,如ASI,AFN(項目中使用這個)
    // ASI:HTTP終結者,已經被淘汰
    // AFN(AFNetworking)\AFN
     // 1.建立請求管理對象
    AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
    
    // 說明服務器返回的爲JSON
     mgr.responseSerializer = [AFJSONResponseSerializer serializer];
    
    // 2.封裝請求參數
    NSMutableDictionary *params = [NSMutableDictionary dictionary];
    params[@"client_id"] = @"2699927613";
    
    params[@"client_secret"] = @"737ea9bf1343d************";
    
    params[@"grant_type"] = @"authorization_code";
    
    params[@"code"] = code;
    
    params[@"redirect_uri"] = @"http://digtime.cn";
    
    
    // 3.發送請求,參數用字典封裝,請求成功後服務器端響應一個對象responseObject
    [mgr POST:@"https://api.weibo.com/oauth2/access_token" parameters: params
      success:^(AFHTTPRequestOperation *operation, id responseObject) {
          // IWLog(@"請求成功:%@", [responseObject class]);從字典中取出數據
          
          // 4.先將字典轉爲模型(建立model,IWAccount.h 取數據放數據很是方便)
          IWAccount *account = [IWAccount accountWithDict:responseObject];
          // NSString *accessToken =  responseObject[@"access_token"];
          
          // 經過返回的數據,判斷受權是否過時,若是過時,則從新受權,打開登錄頁面
          // 5.存儲模型數據---存儲accessToken信息 ---歸檔
          // 5.1獲取沙盒路徑
          NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
          // 5.2 拼接文件路徑
          NSString *file = [doc stringByAppendingPathComponent:@"account.data"];
          [NSKeyedArchiver archiveRootObject:account toFile:file];
          
          // 5.3 Account.h 須要遵照 NSCoding協議,哪些屬性須要歸檔,哪些須要解檔
          // 5.4 而後須要在IWAppDelegate.m代理中當應用加載完後,須要判斷用戶之前是否有登錄成功過,沙盒裏邊有數據,而後判斷沙盒數據受權信息是否有過時,若是沒有過時則直接進入微博
          
          // 6.新特性去首頁
          
          
        
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        IWLog(@"請求失敗:%@", error);

    }];
    
}


帳戶模型:

 IWAccount.h

//
//  IWAccount.h
//  ItcastWeibo
//  賬號模型

#import <Foundation/Foundation.h>

// 須要遵照 NSCoding協議,哪些屬性須要歸檔,哪些須要解檔
@interface IWAccount : NSObject <NSCoding>
@property (nonatomic, copy) NSString *access_token;
// 若是服務器返回的數字很大, 建議用long long(好比主鍵, ID)
@property (nonatomic, assign) long long expires_in;
@property (nonatomic, assign) long long remind_in;
@property (nonatomic, assign) long long uid;

+ (instancetype)accountWithDict:(NSDictionary *)dict;
- (instancetype)initWithDict:(NSDictionary *)dict;
@end


  IWAccount.m 

//
//  IWAccount.m
//  ItcastWeibo
//

#import "IWAccount.h"

@implementation IWAccount
+ (instancetype)accountWithDict:(NSDictionary *)dict{
    return [[self alloc] initWithDict:dict];
}

- (instancetype)initWithDict:(NSDictionary *)dict{
    if(self = [super init]){
        // KVC
        [self setValuesForKeysWithDictionary:dict];
    }
    return self;
}

// 協議方法1-從文件中解析對象的時候調用
-(id)initWithCoder:(NSCoder *)decoder{
    if(self = [super init]){
        self.access_token = [decoder decodeObjectForKey:@"access_token"];
        self.remind_in = [decoder decodeInt64ForKey:@"remind_in"];
        self.expires_in = [decoder decodeInt64ForKey:@"expires_in"];
        self.uid = [decoder decodeInt64ForKey:@"uid"];
    }
    
    return self;
}

// 協議方法2-將對象寫入文件的時候調用
-(void)encodeWithCoder:(NSCoder *)encoder{
    [encoder encodeObject:self.access_token forKey:@"access_token"];
    [encoder encodeInt64:self.remind_in forKey:@"remind_in"];
    [encoder encodeInt64:self.expires_in forKey:@"expires_in"];
    [encoder encodeInt64:self.uid forKey:@"uid"];
    
}


@end


程序代理IWAppDelegate.m中判斷有沒有存儲帳號信息及版本號

//
//  IWAppDelegate.m
//  ItcastWeibo

#import "IWAppDelegate.h"
#import "IWTabBarViewController.h"
#import "IWNewfeatureViewController.h"
#import "IWOAuthViewController.h"
#import "IWAccount.h"

@implementation IWAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    
    // 先判斷有無存儲帳號信息
    NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString *file = [doc stringByAppendingPathComponent:@"account.data"];
    IWAccount *account = [NSKeyedUnarchiver unarchiveObjectWithFile:file];
    
    if (account) { // 以前登陸成功
        NSString *key = @"CFBundleVersion";
        
        // 取出沙盒中存儲的上次使用軟件的版本號
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
        NSString *lastVersion = [defaults stringForKey:key];
        
        // 得到當前軟件的版本號
        NSString *currentVersion = [NSBundle mainBundle].infoDictionary[key];
        
        if ([currentVersion isEqualToString:lastVersion]) {
            // 顯示狀態欄
            application.statusBarHidden = NO;
            self.window.rootViewController = [[IWTabBarViewController alloc] init];
        } else { // 新版本
            self.window.rootViewController = [[IWNewfeatureViewController alloc] init];
            // 存儲新版本
            [defaults setObject:currentVersion forKey:key];
            [defaults synchronize];
        }
    } else { // 以前沒有登陸成功
        self.window.rootViewController = [[IWOAuthViewController alloc] init];
    }
    
    [self.window makeKeyAndVisible];
    return YES;
}


  完整的受權控制器IWOAuthViewController.m代碼:

//
//  IWOAuthViewController.m
//  ItcastWeibo
//

#import "IWOAuthViewController.h"
#import "AFNetworking.h"
#import "IWAccount.h"
#import "IWTabBarViewController.h"
#import "IWNewfeatureViewController.h"

@interface IWOAuthViewController () <UIWebViewDelegate>

@end

@implementation IWOAuthViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // 1.添加webView
    UIWebView *webView = [[UIWebView alloc] init];
    webView.frame = self.view.bounds;
    webView.delegate = self;
    [self.view addSubview:webView];
    
    // 2.加載受權頁面(新浪提供的登錄頁面)
    NSURL *url = [NSURL URLWithString:@"https://api.weibo.com/oauth2/authorize?client_id=2699927613&redirect_uri=http://digtime.cn"];   // 訪問的URL
    NSURLRequest *request = [NSURLRequest requestWithURL:url]; // 請求該URL
    [webView loadRequest:request];
    
   }


#pragma mark - webView代理方法
/**
 *  當webView發送一個請求以前都會先調用這個方法, 詢問代理可不能夠加載這個頁面(請求)
 *
 *  @param request
 *
 *  @return YES : 能夠加載頁面,  NO : 不能夠加載頁面
 */
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    // 1.請求的URL路徑
    NSString *urlStr = request.URL.absoluteString;
    
    // 2.判斷字符串裏邊含有'code='字符,目的是攔截該連接,不讓其自動加載,並獲取code碼
    // http://digtime.cn/?code=8b1c66a777fe49b26fd650a4f2dacd98
     NSRange range = [urlStr rangeOfString:@"code="];
    
    // 3.若是urlStr中包含了code=
    //  if(range.location != NSNotFound)
    if(range.length)
    {
        // 4.獲取code=後面的請求標記(通過用戶受權成功的)
        int loc = range.location + range.length;
        NSString *code = [urlStr substringFromIndex:loc];
        
        // 5.發送POST請求給新浪,經過code換取一個accessToken
        // 發送請求通常用別人封裝好的請求框架
        // ASI:HTTP終結者,已經被淘汰
        // AFN(AFNetworking)\AFN
       
        [self accessTokenWithCode:code];
        
    }
    
    NSLog(@"%@", request.URL);
    
    return YES;
    
}


/**
 *  經過code換取一個accessToken
 redirect_uri	true	string	回調地址,需需與註冊應用裏的回調地址一致。
 */
-(void)accessTokenWithCode:(NSString *)code
{
    // 發送POST請求給新浪,經過code換取一個accessToken
    // 發送請求通常用別人封裝好的請求框架,如ASI,AFN(項目中使用這個)
    // ASI:HTTP終結者,已經被淘汰
    // AFN(AFNetworking)\AFN
     // 1.建立請求管理對象
    AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
    
    // 說明服務器返回的爲JSON
     mgr.responseSerializer = [AFJSONResponseSerializer serializer];
    
    // 2.封裝請求參數
    NSMutableDictionary *params = [NSMutableDictionary dictionary];
    params[@"client_id"] = @"2699927613";
    
    params[@"client_secret"] = @"737ea9bf1343****************";
    
    params[@"grant_type"] = @"authorization_code";
    
    params[@"code"] = code;
    
    params[@"redirect_uri"] = @"http://digtime.cn";
    
    
    // 3.發送請求,參數用字典封裝,請求成功後服務器端響應一個對象responseObject
    [mgr POST:@"https://api.weibo.com/oauth2/access_token" parameters: params
      success:^(AFHTTPRequestOperation *operation, id responseObject) {
          // IWLog(@"請求成功:%@", [responseObject class]);從字典中取出數據
          
          // 4.先將字典轉爲模型(建立model,IWAccount.h 取數據放數據很是方便)
          IWAccount *account = [IWAccount accountWithDict:responseObject];
          // NSString *accessToken =  responseObject[@"access_token"];
          
          // 經過返回的數據,判斷受權是否過時,若是過時,則從新受權,打開登錄頁面
          // 5.存儲模型數據---存儲accessToken信息 ---歸檔
          // 5.1獲取沙盒路徑
          NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
          // 5.2 拼接文件路徑
          NSString *file = [doc stringByAppendingPathComponent:@"account.data"];
          [NSKeyedArchiver archiveRootObject:account toFile:file];
          
          // 5.3 Account.h 須要遵照 NSCoding協議,哪些屬性須要歸檔,哪些須要解檔
          // 5.4 而後須要在IWAppDelegate.m中當應用加載完後,須要判斷用戶之前是否有登錄成功過,沙盒裏邊有數據,而後判斷沙盒數據受權信息是否有過時,若是沒有過時則直接進入微博
          
          // 6.新特性去首頁
          
          
        
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        IWLog(@"請求失敗:%@", error);

    }];
    
}

@end
相關文章
相關標籤/搜索