1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
| // OAuth2Client.m
#import "OAuth2Client.h"
#import "LUKeychainAccess.h"
#import "AFNetworking.h"
static NSString *callback = @"http://localhost";
static NSString *visibleactions = @"http://schemas.google.com/AddActivity";
@implementation OAuth2Client
// シングルトンのインスタンス取得
+ (OAuth2Client *)sharedInstance {
static OAuth2Client* sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [OAuth2Client alloc] init];]
});
return sharedInstance;
}
// OAuth2.0認証に必要なパラメータを設定する処理
- (void)setUpOAuth2AccountClientId:(NSString *)clientId clientSecret:(NSString *)clientSecret scope:(NSString *)scope authorizationURL:(NSString *)authorizationURL tokenURL:(NSString *)tokenURL {
[[LUKeychainAccess standardKeychainAccess] setObject:clientId forKey:@"clientId"];
[[LUKeychainAccess standardKeychainAccess] setObject:clientSecret forKey:@"clientSecret"];
[[LUKeychainAccess standardKeychainAccess] setObject:scope forKey:@"scope"];
[[LUKeychainAccess standardKeychainAccess] setObject:authorizationURL forKey:@"authorizationURL"];
[[LUKeychainAccess standardKeychainAccess] setObject:tokenURL forKey:@"tokenURL"];
}
// OAuth2.0認証に必要なリクエストを生成する処理
- (void)requestAccessToAccount:(void (^)(NSURL *preparedURL))withPreparedAuthorizationURLHandler {
NSString *clientId = [[LUKeychainAccess standardKeychainAccess] objectForKey:@"clientId"];
NSString *scope = [[LUKeychainAccess standardKeychainAccess] objectForKey:@"scope"];
NSString *authorizationURL = [[LUKeychainAccess standardKeychainAccess] objectForKey:@"authorizationURL"];
NSString *url = [[NSString stringWithFormat:@"%@?response_type=code&client_id=%@&redirect_uri=%@&scope=%@&data-requestvisibleactions=%@", authorizationURL, clientId, callback, scope, visibleactions];
withPreparedAuthorizationURLHandler([NSURL URLWithString:url]);
}
// OAuth2.0認証のリダイレクトURIの一致の有無を確認する処理
- (BOOL)checkRedirectURI:(NSURLRequest *)request
{
// HOSTの取得
NSString *host = [[request URL] host];
if ([host isEqualToString:@"localhost"]) {
return YES;
} else {
return NO;
}
}
// アクセストークンを取得する処理
- (void)getAccessToken:(NSURLRequest *)request completionHandler:(void (^)(NSString *accessToken))completionHandler {
NSString *host = [[request URL] host];
if ([host isEqualToString:@"localhost"]) {
NSString* verifier = nil;
NSArray* urlParams = [[request URL] query] componentsSeparatedByString:@"&"];
for (NSString* param in urlParams) {
NSArray* keyValue = [param componentsSeparatedByString:@"="];
NSString* key = [keyValue objectAtIndex:0];
if ([key isEqualToString:@"code"]) {
verifier = [keyValue objectAtIndex:1];
break;
}
}
if (verifier) {
NSString *clientId = [[LUKeychainAccess standardKeychainAccess] objectForKey:@"clientId"];
NSString *clientSecret = [[LUKeychainAccess standardKeychainAccess] objectForKey:@"clientSecret"];
NSString *tokenURL = [[LUKeychainAccess standardKeychainAccess] objectForKey:@"tokenURL"];
// AFHTTPSessionManagerをインスタンス化
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
// サーバエラー時のContent-Typeにtext/plainを許可(成功時にapplication/jsonが必要なので共に追加)
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain", @"application/json", nil];
// パラメータの設定
NSDictionary *data = @{@"code": verifier, @"client_id": clientId, @"client_secret": clientSecret, @"redirect_uri": callback, @"grant_type": @"authorization_code"};
[manager POST:tokenURL parameters:data success:^(NSURLSessionDataTask *task, id responseObject) {
// 成功した場合
if(responseObject && [responseObject count] > 0) {
NSString *accessToken = responseObject[@"access_token"];
NSString *refreshToken = responseObject[@"refresh_token"];
[[LUKeychainAccess standardKeychainAccess] setObject:accessToken forKey:@"accessToken"];
[[LUKeychainAccess standardKeychainAccess] setObject:refreshToken forKey:@"refreshToken"];
// 処理が終了したときに実行(アクセストークンを返す)
completionHandler(accessToken);
}
} failure:^(NSURLSessionDataTask *task, NSError *error) {
// 失敗した場合
NSError *err;
NSData *data = [error userInfo] objectForKey:@"com.alamofire.serialization.response.error.data"];
if(data) {
// エラーの中身がある場合
[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&err];
}
// 失敗を返す
failure(err);
}];
}
} else {
// HOST名が一致しない場合
}
}
// リフレッシュトークンから新しいアクセストークンを取得する処理
- (void)getRefreshAccessToken:(void (^)(NSString *accessToken))success failure:(void (^)(NSError *error))failure {
NSString *clientId = [[LUKeychainAccess standardKeychainAccess] objectForKey:@"clientId"];
NSString *tokenURL = [[LUKeychainAccess standardKeychainAccess] objectForKey:@"tokenURL"];
NSString *refreshToken = [[LUKeychainAccess standardKeychainAccess] objectForKey:@"refreshToken"];
if(clientId && tokenURL && refreshToken) {
// 必須パラメータがある場合
// AFHTTPSessionManagerをインスタンス化
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
// サーバエラー時のContent-Typeにtext/plainを許可(成功時にapplication/jsonが必要なので共に追加)
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain", @"application/json", nil];
// パラメータの設定
NSDictionary *data = @{@"client_id": clientId, @"refresh_token": refreshToken, @"grant_type": @"refresh_token"};
[manager POST:tokenURL parameters:data success:^(NSURLSessionDataTask *task, id responseObject) {
// 成功した場合
if(responseObject && [responseObject count] > 0) {
NSString *accessToken = responseObject[@"access_token"];
NSString *refreshToken = responseObject[@"refresh_token"];
[[LUKeychainAccess standardKeychainAccess] setObject:accessToken forKey:@"accessToken"];
[[LUKeychainAccess standardKeychainAccess] setObject:refreshToken forKey:@"refreshToken"];
// 処理が終了したときに実行(アクセストークンを返す)
success(accessToken);
}
}, failure(NSURLSessionDataTask *task, NSError *error) {
// 失敗した場合
NSError *err;
NSData *data = [error userInfo] objectForKey:@"com.alamofire.serialization.response.error.data"];
if(data) {
// エラーの中身がある場合
[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&err];
}
// 失敗を返す
failure(err);
}];
} else {
// 必須パラメータがない場合
// TODO: エラーオブジェクトを生成して返す
failure(nil);
}
}
@end
|