iOS新浪微博客户端开发(2)——OAuth授权

时间:2022-12-03 04:51:00

一、什么是OAuth?

1、OAuth是一种协议,OAuth协议为用户资源的授权提供了一个安全的、开放而又简易的标准 2、任何服务提供商只要想把自己的用户资源共享出去,都可以实现自身的OAuth认证服务。比如腾讯可以实现自己的OAuth认证服务,把用户的QQ数据共享出去 3、同时,任何第三方都可以使用OAuth认证服务,第三*想访问用户资源,就必须遵守服务提供商实现的OAuth协议总结一下,OAuth可以用来控制用户资源的访问权限。比如我们想访问用户的新浪微博数据,就必须通过新浪实现的OAuth认证。


二、OAuth授权的步骤

1、首先获取未授权的RequestToken:

iOS新浪微博客户端开发(2)——OAuth授权


代码如下:

// 1. 获取未授权的RequestToken,加载登陆界面
NSString *urlStr = [kAuthorizeURL stringByAppendingFormat:@"?display=mobile&client_id=%@&redirect_uri=%@", kAppKey, kRedirectURI];
NSURL *url = [NSURL URLWithString:urlStr];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[_loginWebView loadRequest:request];

2、获取用户授权的RequestToken

iOS新浪微博客户端开发(2)——OAuth授权

代码如下:

#pragma mark 实现代理方法,拦截webView请求,Sent before a web view begins loading a frame.
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
// 1. 获得全路径
NSString *urlStr = request.URL.absoluteString;

// 2. 确定code=的范围
NSRange range = [urlStr rangeOfString:@"code="];

if (range.length != 0) {
// 授权成功,返回NO阻止其加载页面
NSUInteger index = range.location +range.length;

// 得到requestToken
NSString *requestToken = [urlStr substringFromIndex:index];
[self getAccessToken:requestToken];

return NO;
}

return YES; // 授权不成功,跳到回调地址kRedirectURI
}

3、用授权的RequestToken换取AccessToken

iOS新浪微博客户端开发(2)——OAuth授权

代码如下:

#pragma mark 用requestToken换取accessToken
-(void)getAccessToken:(NSString *)requestToken
{
[HttpTool postWithPath:@"oauth2/access_token" params:@{
@"client_id":kAppKey,
@"client_secret":kAppSecret,
@"grant_type":@"authorization_code",
@"redirect_uri":kRedirectURI,
@"code":requestToken} success:^(id JSON) {
// 保存accessToken
AccessToken *accessToken = [[AccessToken alloc]init];
accessToken.accessToken = JSON[@"access_token"];
accessToken.uid = JSON[@"uid"];

[[AccessTokenTool sharedAccessTokenTool]saveAccessToken:accessToken];

// 回到主界面
// ................................................
self.view.window.rootViewController = [[MainViewController alloc]init];

// 隐藏加载动画
[MBProgressHUD hideAllHUDsForView:self.view animated:YES];
} failure:^(NSError *error) {
[MBProgressHUD hideAllHUDsForView:self.view animated:YES];
}];
}

三、归档、获取accessToken

当获取到accessToken后,将其归档存入本地文件中,下次直接从文件中获取accessToken,就不必再输入用户名密码登陆了。

1、首先封装accessToken为AccessToken对象,实现NSCoding协议和其中的方法

.h

#import <Foundation/Foundation.h>

@interface AccessToken : NSObject <NSCoding>
@property (copy, nonatomic) NSString *accessToken;
@property (copy, nonatomic) NSString *uid;
@end
 

.m

#import "AccessToken.h"

@implementation AccessToken

#pragma mark 将accessToken,uid归档
-(void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:_accessToken forKey:@"accessToken"];
[aCoder encodeObject:_uid forKey:@"uid"];
}

#pragma mark 解档
-(id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super init]) {
self.accessToken = [aDecoder decodeObjectForKey:@"accessToken"];
self.uid = [aDecoder decodeObjectForKey:@"uid"];
}
return self;
}

@end

2、实现工具类,其他对象只能通过该工具类获取accessToken,而且该工具类在整个项目中只需创建一次,用单例模式实现

.h

#import <Foundation/Foundation.h>
#import "AccessToken.h"

@interface AccessTokenTool : NSObject

+(AccessTokenTool *)sharedAccessTokenTool;

-(void)saveAccessToken:(AccessToken *)accessToken;

// 当前accessToken
@property (readonly, nonatomic)AccessToken *currentAccessToken;

@end

.m

#import "AccessTokenTool.h"
#import "AccessToken.h"

// 归档文件路径
#define kFilePath [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"accessToke.data"]

static AccessTokenTool *_instace; // 静态实例

@implementation AccessTokenTool

+(AccessTokenTool *)sharedAccessTokenTool
{
@synchronized(self){
if (_instace == nil) {
_instace = [[self alloc]init];
}
}

return _instace;
}

#pragma mark 重写allocWithZone方法
+(id)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instace = [super allocWithZone:zone];
});

return _instace;
}

#pragma mark 重写init方法
-(id)init
{
if (self = [super init]) {
_currentAccessToken = [NSKeyedUnarchiver unarchiveObjectWithFile:kFilePath];
}

return self;
}

-(void)saveAccessToken:(AccessToken *)accessToken
{
_currentAccessToken = accessToken;
[NSKeyedArchiver archiveRootObject:accessToken toFile:kFilePath];
}

@end