一、什么是OAuth?
1、OAuth是一种协议,OAuth协议为用户资源的授权提供了一个安全的、开放而又简易的标准 2、任何服务提供商只要想把自己的用户资源共享出去,都可以实现自身的OAuth认证服务。比如腾讯可以实现自己的OAuth认证服务,把用户的QQ数据共享出去 3、同时,任何第三方都可以使用OAuth认证服务,第三*想访问用户资源,就必须遵守服务提供商实现的OAuth协议总结一下,OAuth可以用来控制用户资源的访问权限。比如我们想访问用户的新浪微博数据,就必须通过新浪实现的OAuth认证。
二、OAuth授权的步骤
1、首先获取未授权的RequestToken:
代码如下:
// 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
代码如下:
#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
代码如下:
#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