How to automatically refresh expired token with AF

2019-03-13 05:48发布

问题:

I'm writing a small iOS client for a server protected with OAuth2.

I'm wondering if is it possible using AFOAuth2Manager [here] auto-refreshing the expired token.

The idea is that the logic for refreshing the client when the server responds with a 401, or raise an error when the refresh method returns a 401 should be quite common, so probably it is integrated in some library.

回答1:

I created a subclass of AFOAuth2Manager

In this subclass I override this method:

- (AFHTTPRequestOperation *)HTTPRequestOperationWithRequest:(NSURLRequest *)request
                                                    success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
                                                    failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure {
    return [self HTTPRequestOperationWithRequest:request
                                         success:success
                                         failure:failure
                           checkIfTokenIsExpired:YES];
}

calling a custom method with an additional parameter: checkIfTokenIsExpired. This is required in order to avoid infinite loops.

The implementation of this method is straigth forward: if we don't need to check the token just call the super class.

if (!checkIfTokenIsExpired) {
        return [super HTTPRequestOperationWithRequest:request
                                              success:success
                                              failure:failure];
    }

otherwise we perform the request with a custom failure block

else {
        return [super HTTPRequestOperationWithRequest:request
                                              success:success
                                              failure: ^(AFHTTPRequestOperation *operation, NSError *error) {
            if (operation.response.statusCode == ERROR_CODE_UNAUTHORIZED) { //1
                [self reauthorizeWithSuccess: ^{ //2
                    NSURLRequest *req = [self.requestSerializer requestByAddingHeadersToRequest:request]; //3
                    AFHTTPRequestOperation *moperation = [self HTTPRequestOperationWithRequest:req //4
                                                                                       success:success
                                                                                       failure:failure
                                                                         checkIfTokenIsExpired:NO];

                    [self.operationQueue addOperation:moperation]; //5
                }                    failure: ^(NSError *error) {
                    failure(nil, error);
                }];
            }
            else {
                failure(operation, error); //6
            }
        }];
    }
  • //1: check the http status code, if 401 try to automatically re-authorize.
  • //2: reauthorize is a private mathod that uses AFOAuthManager to refresh the token.
  • //3: In this case we are re-authorized with success and we want to resubmit a copy of the previous request. The method requestByAddingHeadersToRequest: just copy all the header fields from the previous request.
  • //4: Create a copy of the previous request, but this time the last parameter is false because we don't want check again! The successBlock and failureBlock are the same of the previous request.
  • //5: Add the operation to the queue.
  • //6: If the reauthorize method fails just call the failure block.


回答2:

Unfortunately I didn't found any framework for solve this problem so I wrote a short wrapper around AFNetworking (if someone is interested I can publish on github) The logic is to execute the request, and in case of http response 401, try to refresh the auth-token and when it's done to re-execute the previous request.



回答3:

I was searching an answer for this problem and "Matt", the creator of AFNetworking, suggest this:

the best solution I've found for dealing with this is to use dependent NSOperations to check for a valid, un-expired token before any outgoing request is allowed to go through. At that point, it's up to the developer to determine the best course of action for refreshing the token, or acquiring a new one in the first place.

Simple, but effective?, trying now, will edit with report...



回答4:

Swift solution with Alamofire 4.0. Based on RequestAdapter and RequestRetrier protocols: example link