申请开发者

想要拉到到新浪微博的数据,首先让自己成为开发者。申请成为开发者账号很简单,只要有新浪微博的账号即可。

申请地址:http://open.weibo.com/

在开发的过程中,我们需要拿到几下几个值:

AppKey :分配给每个第三方应用的 app key。用于鉴权身份,显示来源等功能。

AppSecret :分配给每个第三方应用的 app 私钥。

RedirectURI:应用回调页面,可在新浪微博开放平台->我的应用->应用信息->高级应用->授权设置->应用回调页中找到。

为了方便测试,除了可以使用当前开发者账户外,还可以自己添加15个关联测试账号。

开发实现

授权相关文档:http://open.weibo.com/wiki/%E6%8E%88%E6%9D%83%E6%9C%BA%E5%88%B6

实现思路:

  1. 拼接参数,请求OAuth2/authorize ,拿到授权Code值。
  2. 通过授权code值及相关申请的参数,拿到用户授权UID及过期时间
  3. 将返回的用户信息存入沙盒里
  4. 下次打开应用时,先从沙盒里获取,获取为nil时再请求网络

导入相关第三方库

直接在cocoapods里导入以下的类库

  • 网络请求:AFNetworking
  • 吐丝:MBProgressHUD
platform :ios,'7.0'
pod "AFNetworking","2.5.4"
pod 'MBProgressHUD', '~> 0.9.1'

由于在很多地方都会使用到AFNetworking,为了不让该第三方库类“污染”,特意给AFNetworking封装一层,方便以后切换第三方网络请求类,同时也方便引用管理。

HttpTool.h

#import <Foundation/Foundation.h>

@interface HttpTool : NSObject

+ (void)get:(NSString *)url params:(NSDictionary *)params success:(void (^)(id json))success failure:(void (^)(NSError *error))failure;
+ (void)post:(NSString *)url params:(NSDictionary *)params success:(void (^)(id json))success failure:(void (^)(NSError *error))failure; @end

HttpTool.m

#import "HttpTool.h"
#import "AFNetworking.h" @implementation HttpTool + (void)get:(NSString *)url params:(NSDictionary *)params success:(void (^)(id json))success failure:(void (^)(NSError *error))failure
{
// 1.创建请求管理者
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager]; mgr.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/html", @"text/json", @"text/javascript",@"text/plain", nil]; // 2.发送请求
[mgr GET:url parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
if (success) {
success(responseObject);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (failure) {
failure(error);
}
}];
} + (void)post:(NSString *)url params:(NSDictionary *)params success:(void (^)(id json))success failure:(void (^)(NSError *error))failure
{
// 1.创建请求管理者
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager]; mgr.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/html", @"text/json", @"text/javascript",@"text/plain", nil]; // 2.发送请求
[mgr POST:url parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
if (success) {
success(responseObject);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (failure) {
failure(error);
}
}];
} @end

定义账户常量

申请下来的账号信息,我们使用常用来存储,当然,一些常用的不变的通用字符串,我们也统一放在常量里,需要避免使用宏。可以参考:http://www.jianshu.com/p/f83335e036b5

Const.h

#import <Foundation/Foundation.h>

extern NSString * const AppKey;
extern NSString * const RedirectURI;
extern NSString * const AppSecret;

Const.m

#import "Const.h"

// 账号信息
NSString * const AppKey = @"";
NSString * const RedirectURI = @"http://www.baidu.com";
NSString * const AppSecret = @"89d739c387e3a69aaad0270da66c02ff";

归档access_token工具类

由于access_token不经常变,我们需要将拿到的access_token归档存起来,每次登录的时候,先判断access_token是否有效(存在且不过期)。

归档使用模型,需要实现NSCoding协议,定义模型

Account.h

#import <Foundation/Foundation.h>

@interface Account : NSObject<NSCoding>

/** string    用于调用access_token,接口获取授权后的access token。*/
@property (nonatomic, copy) NSString *access_token; /** string access_token的生命周期,单位是秒数。*/
@property (nonatomic, copy) NSNumber *expires_in; /** string 当前授权用户的UID。*/
@property (nonatomic, copy) NSString *uid; /** access token的创建时间 */
@property (nonatomic, strong) NSDate *created_time; /** 用户的昵称 */
@property (nonatomic, copy) NSString *name; + (instancetype)accountWithDict:(NSDictionary *)dict; @end

Account.m

#import "Account.h"

@implementation Account

+(instancetype)accountWithDict:(NSDictionary *)dict
{
Account *account = [[self alloc] init];
account.access_token = dict[@"access_token"];
account.uid = dict[@"uid"];
account.expires_in = dict[@"expires_in"];
// 获得账号存储的时间(accessToken的产生时间)
account.created_time = [NSDate date];
return account;
} /**
* 当一个对象要归档进沙盒中时,就会调用这个方法
* 目的:在这个方法中说明这个对象的哪些属性要存进沙盒
*/
- (void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeObject:self.access_token forKey:@"access_token"];
[encoder encodeObject:self.expires_in forKey:@"expires_in"];
[encoder encodeObject:self.uid forKey:@"uid"];
[encoder encodeObject:self.created_time forKey:@"created_time"];
[encoder encodeObject:self.name forKey:@"name"];
} /**
* 当从沙盒中解档一个对象时(从沙盒中加载一个对象时),就会调用这个方法
* 目的:在这个方法中说明沙盒中的属性该怎么解析(需要取出哪些属性)
*/
- (id)initWithCoder:(NSCoder *)decoder
{
if (self = [super init]) {
self.access_token = [decoder decodeObjectForKey:@"access_token"];
self.expires_in = [decoder decodeObjectForKey:@"expires_in"];
self.uid = [decoder decodeObjectForKey:@"uid"];
self.created_time = [decoder decodeObjectForKey:@"created_time"];
self.name = [decoder decodeObjectForKey:@"name"];
}
return self;
} @end

为了方便直接归档和从归档里读取模型,定义一个AccountTool工具类

AccountTool.h

#import <Foundation/Foundation.h>
#import "Account.h" @interface AccountTool : NSObject /**
* 存储账号信息
*
* @param account 账号模型
*/
+ (void)saveAccount:(Account *)account; /**
* 返回账号信息
*
* @return 账号模型(如果账号过期,返回nil)
*/
+ (Account *)getAccount; @end

AccountTool.m

//
// AccountTool.m
// Weibo
//
// Created by jiangys on 15/10/17.
// Copyright © 2015年 Jiangys. All rights reserved.
// #import "AccountTool.h"
#import "Account.h" // 账号的存储路径
#define AccountPath [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"account.archive"] @implementation AccountTool /**
* 存储账号信息
*
* @param account 账号模型
*/
+ (void)saveAccount:(Account *)account
{
// 自定义对象的存储必须用NSKeyedArchiver,不再有什么writeToFile方法
[NSKeyedArchiver archiveRootObject:account toFile:AccountPath];
} /**
* 返回账号信息
*
* @return 账号模型(如果账号过期,返回nil)
*/
+ (Account *)getAccount
{
// 加载模型
Account *account = [NSKeyedUnarchiver unarchiveObjectWithFile:AccountPath]; /* 验证账号是否过期 */ // 过期的秒数
long long expires_in = [account.expires_in longLongValue];
// 获得过期时间
NSDate *expiresTime = [account.created_time dateByAddingTimeInterval:expires_in];
// 获得当前时间
NSDate *now = [NSDate date]; // 如果expiresTime <= now,过期
/**
NSOrderedAscending = -1L, 升序,右边 > 左边
NSOrderedSame, 一样
NSOrderedDescending 降序,右边 < 左边
*/
NSComparisonResult result = [expiresTime compare:now];
if (result != NSOrderedDescending) { // 过期
return nil;
} return account;
} @end

获取并存储access_token

控制器需要调用authorize获得的code值,再通过code值获取access_token

OAuthViewController.h

#import <UIKit/UIKit.h>

@interface OAuthViewController : UIViewController

@end

OAuthViewController.m

//
// OAuthViewController.m
// Weibo
//
// Created by jiangys on 15/10/17.
// Copyright © 2015年 Jiangys. All rights reserved.
// #import "OAuthViewController.h"
#import "Const.h"
#import "HttpTool.h"
#import "MBProgressHUD+YS.h"
#import "Account.h"
#import "AccountTool.h" @interface OAuthViewController() <UIWebViewDelegate> @end @implementation OAuthViewController - (void)viewDidLoad
{
[super viewDidLoad]; // 1.创建一个webView
UIWebView *webView=[[UIWebView alloc] init];
webView.frame=self.view.bounds;
webView.delegate=self;
[self.view addSubview:webView]; // 2.用webView加载新浪登录页面
NSString *urlStr=[NSString stringWithFormat:@"https://api.weibo.com/oauth2/authorize?client_id=%@&redirect_uri=%@",AppKey,RedirectURI];
NSURLRequest *requestUrl=[NSURLRequest requestWithURL:[NSURL URLWithString:urlStr]];
[webView loadRequest:requestUrl];
} #pragma mark - webView代理方法
-(void)webViewDidStartLoad:(UIWebView *)webView
{
[MBProgressHUD showMessage:@"正在加载..."];
} -(void)webViewDidFinishLoad:(UIWebView *)webView
{
[MBProgressHUD hideHUD];
} -(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
[MBProgressHUD hideHUD];
} /**
* 监听所有跳转方法
*/
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSString *url=request.URL.absoluteString;
NSRange range=[url rangeOfString:@"code="];
if (range.length != ) {
// 截取code=后面的参数值
NSUInteger fromIndex=NSMaxRange(range);
NSString *code=[url substringFromIndex:fromIndex]; // 利用code换取一个accessToken
[self accessTokenWithCode:code]; // 禁止加载回调地址
return NO;
} return true;
} /**
* 获取token
*
* @param code 授权码
*/
- (void)accessTokenWithCode:(NSString *)code
{
NSMutableDictionary *params=[NSMutableDictionary dictionary];
params[@"client_id"] = AppKey;
params[@"client_secret"] = AppSecret;
params[@"grant_type"] = @"authorization_code";
params[@"redirect_uri"] = RedirectURI;
params[@"code"] = code; [HttpTool post:@"https://api.weibo.com/oauth2/access_token" params:params success:^(id json)
{
[MBProgressHUD hideHUD]; // 将返回的账号字典数据 --> 模型,存进沙盒
Account *account = [Account accountWithDict:json]; // 存储账号信息
[AccountTool saveAccount:account]; // 切换窗口的根控制器
UIWindow *window = [UIApplication sharedApplication].keyWindow;
[window switchRootViewController]; }failure:^(NSError *error) {
[MBProgressHUD hideHUD];
YSLog(@"--MBProgressHUD_error--%@",error);
}];
} @end

登录验证access_token

每次登录的时候,都需要判断access_token是否有效(存在且不过期)

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    self.window=[[UIWindow alloc]init];
self.window.frame=[UIScreen mainScreen].bounds; // 2.设置根控制器
Account *account = [AccountTool getAccount];
if (account) { // 之前已经登录成功过
[self.window switchRootViewController];
} else {
self.window.rootViewController = [[OAuthViewController alloc] init];
} [self.window makeKeyAndVisible]; return YES;
}

章节源代码下载:http://pan.baidu.com/s/1sjmoEw1

新浪微博Github:https://github.com/jiangys/Weibo

iOS 新浪微博-4.0 OAuth授权的更多相关文章

  1. [iOS微博项目 - 2.0] - OAuth授权3步

    A.概念      OAUTH协议为用户资源的授权提供了一个安全的.开放而又简易的标准.与以往的授权方式不同之处是OAUTH的授权不会使第三方触及到用户的帐号信息(如用户名与密码),即第三方无需使用用 ...

  2. 新浪微博开放平台OAuth授权解决方案(含代码)

    前几日一位朋友项目中需要使用新浪微博的接口,故和这位朋友一同研究了新浪微博开放平台上面所提供的资料,首先要使用这些接口是需要用户登录并且授权的,新浪微博开放平台其实是提供两种授权方式的,第一种是:OA ...

  3. IOS第四天-新浪微博 -存储优化OAuth授权账号信息,下拉刷新,字典转模型

    *************application - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOpti ...

  4. iOS 新浪微博-5.0 首页微博列表

    首页显示微博列表,是微博的核心部分,这一章节,我们主要是显示出微博的列表. 导入第三方类库 pod 'SDWebImage', '~> 3.7.3' pod 'MJRefresh', '~> ...

  5. iOS 新浪微博-3.0 新特性

    每个程序在第一次启动的时候,都会显示新特性.效果如下: 思路: 添加一个ViewController,里面放两个View,一个是UISrollView,另一个pageControl 往UISrollV ...

  6. iOS 新浪微博-2.0 搜索框/标题带箭头/下拉菜单

    不管是搜索框还是下拉菜单,我们都需要对背景的图片进行拉伸.定义一个Category分类对图片进行操作. UIImage+Effect.h #import <UIKit/UIKit.h> @ ...

  7. iOS新浪微博OAuth2.0认证代码

    #import "ViewController.h" #import "AFNetworking.h" @interface ViewController () ...

  8. iOS之新浪微博的OAuth授权

    新浪微博的OAuth授权 之前通过新浪微博开发平台写过微博的的项目,现在就开始总结下各个方面的知识点,一个是为了加深印象.巩固知识,另一个记录自己学习过程,希望自己在开发这条路上有所积累,为以后的道路 ...

  9. IOS第三天-新浪微博 - 版本新特性,OAuth授权认证

    *********版本新特性 #import "HWNewfeatureViewController.h" #import "HWTabBarViewController ...

随机推荐

  1. HDU 1166 - 敌兵布阵 - [分块]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1166 题解: 本题作为一个模板题,我用它来检验过总查询时间复杂度为 $O(q \log n)$ 的树状 ...

  2. [No000013C]B树、B-树、B+树、B*树

    B树 即二叉搜索树: 1.所有非叶子结点至多拥有两个儿子(Left和Right): 2.所有结点存储一个关键字: 3.非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树: 如: B ...

  3. [No0000127]WCF安全体系netTCPBinding绑定

    netTCPBinding绑定之Transport安全模式 一.netTCPBinding 此绑定使用TCP传输协议,不具交互性,只适用于 WCF 到 WCF 的通信. 此绑定的传输安全性的实现:  ...

  4. 1.7Oob 继承关系中构造方法的使用

    1:父类中最好要有一个空参数的构造方法,因为默认的构造方法在自定义了构造方法后就不存在了,需要显示的写出来. 若父类中没有空参数的构造方法,则子类必须有自定义的构造方法,且用super()调用父类的构 ...

  5. 用CSS画基本图形

    用CSS画基本图形 1.正方形 代码如下: #square { width: 100px; height: 100px; background: red; } 2.长方形 代码如下:   #recta ...

  6. 访问Google的办法

    访问Google的办法 http://www.liu16.com/g.html http://ac.scmor.com/ https://www.elastic.co/guide/en/elastic ...

  7. wslgit

    @echo off setlocal enabledelayedexpansion set command=%* If %PROCESSOR_ARCHITECTURE% == x86 ( echo | ...

  8. 在计算机通信中,可靠交付应当由谁来负责?是网络还是端系统? 网络层协议 MAC帧、IP数据报、TCP报文 关系 IP地址与硬件地址 链路层与网络层

    小结: 1. 网络层两种服务 虚电路服务 virtual circuit  电信网 网络层负责可靠交付 数据报服务  网络层不负责可靠交付 提供灵活的.无连接的.尽最大努力交付的数据报服务 不提供服务 ...

  9. [elastic search][redis] 初试 ElasticSearch / redis

    现有项目组,工作需要. http://www.cnblogs.com/xing901022/p/4704319.html Elastic Search权威指南(中文版) https://es.xiao ...

  10. LeetCode 682 Baseball Game 解题报告

    题目要求 You're now a baseball game point recorder. Given a list of strings, each string can be one of t ...