我有一台服务器,其中实现了OAuth 2.0以发布访问权限和刷新令牌。该服务器的客户端是用Objective-C编写的iOS应用程序。我目前正在使用AFNetworking 3.0进行HTTP请求,使用AFOAuth2Manager来处理授权。我想在访问令牌到期之前使用服务器发出的刷新令牌刷新存储在iOS应用程序中的访问令牌(服务器返回到期的秒数为{'expires_in':3600}(一小时))。在访问令牌到期之前,一切正常。以下是处理请求和授权的代码。
- (AFJSONRequestSerializer *)setRequestSerializer
{
AFJSONRequestSerializer *serializer = [AFJSONRequestSerializer serializer];
[serializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[serializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];
User *currentUser = [User currentUser];
if (currentUser){
AFOAuthCredential *credentials = [AFOAuthCredential retrieveCredentialWithIdentifier:kEndpointServer];
if (!credentials.isExpired){
[serializer setAuthorizationHeaderFieldWithCredential:credentials];
}
}
return serializer;
}
- (AFJSONResponseSerializer *)setResponseSerializer
{
AFJSONResponseSerializer *serializer = [AFJSONResponseSerializer serializer];
return serializer;
}
- (AFSecurityPolicy *)setSecurityPolicy
{
NSString *certFilePath = [[NSBundle mainBundle] pathForResource:@"cert" ofType:@"cer"];
NSData *certData = [NSData dataWithContentsOfFile:certFilePath];
NSSet *pinnedCerts = [NSSet setWithObject:certData];
AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:pinnedCerts];
[policy setAllowInvalidCertificates:YES]; // DEVELOPMENT ONLY
[policy setValidatesDomainName:NO];
return policy;
}
- (AFHTTPSessionManager *)sessionManager
{
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.securityPolicy = [self setSecurityPolicy];
manager.requestSerializer = [self setRequestSerializer];
manager.responseSerializer = [self setResponseSerializer];
return manager;
}
- (AFOAuth2Manager *)OAuth2Manager
{
NSURL *baseURL = [NSURL URLWithString:kEndpointServer];
AFOAuth2Manager *manager = [[AFOAuth2Manager alloc] initWithBaseURL:baseURL clientID:kParamAPIClientId secret:kParamAPIClientSecret];
manager.securityPolicy = [self setSecurityPolicy];
return manager;
}
- (void)loginUser:(NSDictionary *)user block:(void (^)(BOOL, NSError *))result
{
// Set endpoint URL
NSString *loginEndpointURL = [NSString stringWithFormat:@"%@%@", kEndpointServer, kEndpointLogin];
AFHTTPSessionManager *manager = [self sessionManager];
if ([self internetConnectionAvailable]){
[manager POST:loginEndpointURL parameters:user progress:nil success:^(NSURLSessionDataTask *task, id responseObject){
NSDictionary *responseDict = (NSDictionary *)responseObject;
BOOL success = (BOOL)[(NSNumber *)[responseDict objectForKey:kParamSuccess] boolValue];
NSString *msg = (NSString *)[responseDict objectForKey:kParamMessage];
if (success){
// Get user
NSDictionary *userLoggedIn = (NSDictionary *)[responseDict objectForKey:kParamUser];
//NSLog(@"Logged in.");
NSString *tokenEndpointURL = [NSString stringWithFormat:@"/api%@%@", kEndpointOAuth, kEndpointToken];
OAuth2Manager *OAuth2Manager = [self OAuth2Manager];
[OAuth2Manager authenticateUsingOAuthWithURLString:tokenEndpointURL username:(NSString *)[user objectForKey:kParamEmail] password:(NSString *)[user objectForKey:kParamPassword] scope:nil success:^(AFOAuthCredential *credentials){
NSLog(@"Credentials:");
NSLog(@"Access Token: %@", credentials.accessToken);
NSLog(@"Refresh Token: %@", credentials.refreshToken);
// Store credentials
[AFOAuthCredential storeCredential:credentials withIdentifier:kEndpointServer];
// Set current user
[User setCurrentUser:userLoggedIn];
result(YES, nil);
}failure:^(NSError *error){
NSLog(@"Error authenticating user: %@", error);
result(NO, error);
}];
} else {
result(NO, [NSError errorWithDomain:msg code:kEDHTTPRequestFailedErrorCode userInfo:nil]);
}
}failure:^(NSURLSessionDataTask *task, NSError *error){
result(NO, error);
}];
} else {
result(NO, [NSError errorWithDomain:kEDNoInternetConnectionErrorDomain code:kEDNoInternetConnectionErrorCode userInfo:nil]);
}
}
我在SO上发现了类似的问题:
How to automatically refresh expired token with AFOAuth2Manager?
但给出答案的问题是它已经过时(适用于AFNetworking 2.X.X,但不适用于AFNetworking 3.0)。
自动处理访问令牌刷新的最佳做法是什么?