我的应用程序具有相当简单的授权/身份验证,需要一些有关如何处理授权生命周期的帮助。这是它的主旨:
这里有一些代码,代表了我现在能想到的最好的代码。
static NSString * _authorizationToken;
@implementation MyRestfulModel
+ (id) sharedRestfulModel
{
// singleton model shared across view controllers
static MyRestfulModel * _sharedModel = nil;
@synchronized(self) {
if (_sharedModel == nil)
_sharedModel = [[self init] alloc];
}
return _sharedModel;
}
+ (NSString *) authorizationToken
{
if (!_authorizationToken)
_authorizationToken = @"";
return _authorizationToken;
}
+ (void) setAuthorizationToken: (NSString *token)
{
_authorizationToken = token;
}
-(void) doSomeRestfulCall: (NSString *) restURL
completionHandler: (void (^)(NSData * data)) callback
{
// construct url path and request
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:restURL];
[request setValue:MyRestfulModel.authorizationToken forHTTPHeaderField:@"Authorization"];
[[[NSURLSession sharedSession] dataTaskWithRequest: request
completionHandler:^(NSData *data, NSURLResponse * response, NSError * error) {
NSHTTPResponse * httpResponse = (NSHTTPResponse *) response;
if([httpResponse statusCode] == 401) { // WHAT TO DO HERE ?
dispatch_sync(dispatch_get_main_queue(), ^{
MyAppDelegate * delegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
[delegate showLoginViewController callback:^(NSString * username, NSString * newToken) {
// recreate the NSURLSession and NSURLConfiguration with the new token and retry
MyRestfulModel.authenticationToken = token;
[self doSomeRestfulCall:callback];
}];
}
return;
} else {
callback(data);
}
}] resume];
}
我希望这样做,以便视图控制器永远不必担心由于令牌过期而重试呼叫,所有可怕的会话处理和身份验证都可以由一个对象完成。
我正在考虑尝试使用NSURLSessionDelegate,但我无法弄清楚w.r.t中的didReceiveChallenge部分。弹出登录视图控制器。我正在考虑的另一个选项是添加一个类似于完成处理程序的“retryHandler”,它将在用户重新进行身份验证后调用。
答案 0 :(得分:0)
我想我找到了一个很好的解决方案。以“doSomeRestfulCall”方法为例。
-(void) doSomeRestfullCall: (NSString *) restURL
completionHandler: (void (^)(NSData * data)) callback
{
// construct url path and request
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:restURL];
[request setValue:MyRestfulModel.authorizationToken forHTTPHeaderField:@"Authorization"];
[[[NSURLSession sharedSession] dataTaskWithRequest: request
completionHandler:^(NSData *data, NSURLResponse * response, NSError * error) {
NSHTTPResponse * httpResponse = (NSHTTPResponse *) response;
if([httpResponse statusCode] == 401) {
[LoginViewController showWithCompletion:^(NSString *username, NSString *token) {
NSLog(@"Retrying request after user reauthenticated");
MyRestfulModel.authorizationToken = token;
[self doSomeRestfulCall:restURL completionHandler:callback];
}];
return;
} else {
callback(data);
}
}] resume];
}
然后登录视图控制器就会发生很多魔法。 (如果您不想要自定义登录控制器,也可以使用警报视图,请查看此帖子:http://nscookbook.com/2013/04/ios-programming-recipe-22-simplify-uialertview-with-blocks/)
@interface LoginViewController
@property (copy) void(^completionBlock)(NSString * username, NSString * tokenCredentials);
@end
@implementation LoginViewController
+ (void) showWithCompletion: (void (^)(NSString * username, NSString * tokenCredentials))completion
{
AppDelegate * appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
UIViewController * rootController = appDelegate.window.rootViewController;
UIStoryboard * storyboard = rootController.storyboard;
LoginViewController * controller = [storyboard instantiateViewControllerWithIdentifier:@"Login"];
controller.completionBlock = completion;
controller.delegate = wrapper;
controller.modalPresentationStyle = UIModalPresentationFormSheet;
[rootController presentViewController:controller animated:YES completion:nil];
}
//
// <code for contacting your authentication service>
//
-(void) loginSuccessful: (NSString *) username withTokenCredentials:(NSString *)token
{
// <code to store username and token in the keychain>
if (self.completionBlock)
self.completionBlock(username, token);
}