iOS接入快盤的HMAC-SHA1授權(quán)認證失敗解決方案

最近幫別人看了一個使用HMAC-SHA1 進行加密授權(quán)快盤的一個認證,經(jīng)過測試,第一步獲取 oAuth-token 就會出現(xiàn)錯誤,錯誤原因是,簽名失敗,也就是說我們的簽名某個地方錯誤了,簽名這個地方看著好做,其實一步走錯,就會全部錯哦,我們就完全跳進坑了


一、 下面我們看一下,第一步我們要怎么去接入快盤

  1. 點擊進入快盤開發(fā)者中心
  2. 我們進行一個賬號注冊,添加一個應(yīng)用 后然后獲取對應(yīng)的 auth_consumer_keyconsumer_secret
  3. 點擊進入開發(fā)者文檔一欄,這些文檔可以在使用的時候慢慢研究
  4. 點擊 左側(cè)的 OAuth 協(xié)議 【RFC58493.4 HMAC-SHA1】最下面的簽名生成算法

我們會看到如下幾個重要的地方

第一步授權(quán)重要步驟

其實這個加密規(guī)則還算簡單,就是encode 稍微有點麻煩,我們感覺快盤的其實只是提供了一些API接口,并沒有什么SDK,所以我們要完全按照文檔提示的操作步驟走

二、簽名算法的生成

  • 我們先了解一下官方API的簽名,官方提供給我們的是Python 寫的實例,有些不懂的似乎看的不是太懂。我們看下官方提供的思路
假設(shè)服務(wù)器地址為 openapi.kuaipan.cn,現(xiàn)在需要向 
http://openapi.kuaipan.cn/1/fileops/create_folder 用GET方法發(fā)
出請求,請求參數(shù) (parameters) 如下:
{
        'oauth_version': '1.0', 
        'oauth_token': 'fa361a4a1dfc4a739869020e586582f9', 
        'oauth_signature_method': 'HMAC-SHA1', 
        'oauth_nonce': '58456623', 
        'oauth_timestamp': 1328881571, 
        'oauth_consumer_key': '79a7578ce6cf4a6fa27dbf30c6324df4', 
        'path': '/test@kingsoft.com', 
        'root': 'kuaipan'
}
//Python  簽名加密格式:
http_method + "&" +
url_encode( base_uri ) + "&" +
url_encode(
        “&”.join(
                sort( [url_encode ( k ) + "=" +url_encode ( v ) for k, v in paramesters.items() ]
        )
)



我們將加密規(guī)則翻譯過來看一下iOS中我們要如何寫(拼接字符串參數(shù)) 步驟如下:(下面步驟都是拼接關(guān)系,我們進行拆分)

  1. HTTPMethod: GET 大寫
  2. 地址符號: &
  3. url_encode: base_uri utf8string] 對基地址進行URL編碼
  4. join 前面的&:此處表示將一個數(shù)組拼接起來的意思,緊跟后面的sort 函數(shù)結(jié)果 ,并不是 此處用 & 去連接
  5. sort : 按照官方給予的解釋就是將參數(shù)按照 字典的ASCII 碼進行Key值排序,例子給出的是升序排列組合, Python 所謂的字典就是Map 集合,OC對應(yīng)的就是NSDictionary -字典
  6. sort函數(shù)內(nèi)部: 里面的for 循環(huán)代表是循環(huán)遍歷字典,并且每個鍵值對 都進行一次URL encode。循環(huán)之后的鍵值對經(jīng)過 & 進行連接到一起
  7. 最終我們將4、5、6的最終拼接完成的字符串,再次經(jīng)過一次URL ,encdoe ,就得到官方所說的原串的編碼拼接完畢。

我們看一下官方生成的簽名格式:

GET&http%3A%2F%2Fopenapi.kuaipan.cn%2F1%2Ffileops%2Fcre
ate_folder&oauth_consumer_key%3D79a7578ce6cf4a6fa27
dbf30c6324df4%26oauth_nonce%3D58456623%26oauth_signat
ure_method%3DHMAC-
SHA1%26oauth_timestamp%3D1328881571
%26oauth_token%3Dfa361a4a1dfc4a739869020e586582f9%26
oauth_version%3D1.0%26path%3D%252Ftest%2540kingsoft.co
m%26root%3Dkuaipan

原串編碼組合完畢形式如上所示:

  • 原串編碼完畢,我們使用HMAC-SHA1進行秘鑰加密:
  1. 生成簽名加密的秘鑰,格式如下:
    然后生成簽名加密的密鑰(記得有個&),注意假如沒有 oauth_token的話,"&"之后的部分是不用包含的:
    c7ed87c12e784e48983e3bcdc6889dad&0183ce137e4d4170b2ac19d3a9fda677
  2. 使用密鑰通過HMAC-SHA1算法簽名字符基串,生成簽名(先生成數(shù)字簽名,然后再用base64 encode):
    pa7Fuh9GQnsPc+Lcn+Qu6G7LVEU=
  3. 最后把urlencode后的簽名作為oauth_signature的值,向連接發(fā)出請求:
    url_encode(auth_signature) 進行最后一次編碼,現(xiàn)在就可以直接發(fā)送請求了:
    通過終端或者通過官方提供的平臺都可以測試:
    終端命令:
curl –k 
"http://openapi.kuaipan.cn/1/fileops/create_folder?oauth_version=1.0&oauth_signature=pa7Fuh9GQnsPc%2BLcn
%2BQu6G7LVEU%3D&oauth_token=fa361a4a1dfc4a739869020e586582f9&oauth_signature_method=HMAC-SHA1&oauth_nonc
e=58456623&oauth_timestamp=1328881571&path=%2Ftest%40kingsoft.com&oauth_consumer_key=79a7578ce6cf4a6fa27
dbf30c6324df4&root=kuaipan"

三、iOS中如何去操作這些加密規(guī)則?

我們直接代碼接入測試:

  1. 準備好申請的Key 和 Secret ,我們這里只做第一步的簽名認證:
    獲取requestToken
    baseUri :
static NSString  * baseUrl = @"https://openapi.kuaipan.cn/open/requestToken";

參數(shù)準備:

 NSDictionary * prama = @{@"oauth_consumer_key":@"xcVaIWFCPRTVabGH",
                              @"oauth_signature_method":@"HMAC-SHA1",
                              @"oauth_timestamp":[self dateString],
                              @"oauth_nonce":[self onceString],
                              @"oauth_version":@"1.0",
                              };

涉及到的兩個方法 dateStringonceString

- (NSString *)dateString{
    NSDate* dat = [NSDate dateWithTimeIntervalSinceNow:0];
    NSTimeInterval a=[dat timeIntervalSince1970]*1000;
    NSString *timeString = [NSString stringWithFormat:@"%.f", a];

    NSRange rang = {0,10};
    NSString *subString = [timeString substringWithRange:rang];

    return subString;
}

- (NSString *)onceString{
    NSString *string = [[NSString alloc]init];
    for (int i = 0; i<8; i++) {
        int number = arc4random() % 25;
        if (number < 10) {
            int figure = (arc4random() % 26) + 97;
            char character = figure;
            NSString *tempString = [NSString stringWithFormat:@"%c", character];
            string = [string stringByAppendingString:tempString];
            if (figure%2==0) {
                [string uppercaseString];
            }
        }else {

            int figure = arc4random() % 10;
            NSString *tempString = [NSString stringWithFormat:@"%d", figure];
            string = [string stringByAppendingString:tempString];
        }
    }
    return string;

}

我們所用到的URL——Encode方法如下

- (NSString *)encodeToPercentEscapeString: (NSString *) input
{
    NSString*
    outputStr = (__bridge NSString *)CFURLCreateStringByAddingPercentEscapes(

                                                                             NULL, /* allocator */

                                                                             (__bridge CFStringRef)input,

                                                                             NULL, /* charactersToLeaveUnescaped */

                                                                             (CFStringRef)@"!*'();:@&=+$,/?%#[]",
                                                                             
                                                                             kCFStringEncodingUTF8);
    
    
    return  outputStr;
}

HMAC-SHA1 簽名之后,使用Base64編碼
簽名格式: HMAC-SHA1(原串,秘鑰) -> Base64 編碼
使用HMAC,時需要導(dǎo)入一下兩個類庫

#import <CommonCrypto/CommonHMAC.h>
#import <CommonCrypto/CommonCryptor.h>
+ (NSString *)hmac_sha1:(NSString *)key text:(NSString *)text{

    const char *cKey  = [key cStringUsingEncoding:NSUTF8StringEncoding];
    const char *cData = [text cStringUsingEncoding:NSUTF8StringEncoding];

    char cHMAC[CC_SHA1_DIGEST_LENGTH];

    CCHmac(kCCHmacAlgSHA1, cKey, strlen(cKey), cData, strlen(cData), cHMAC);

    NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC length:CC_SHA1_DIGEST_LENGTH];
    NSString *hash = [HMAC base64Encoding];//base64Encoding函數(shù)在NSData+Base64中定義(NSData+Base64網(wǎng)上有很多資源)

    return hash;
}
  • 下面我們進行對參數(shù)進行排序:代碼如下:
 NSArray * keyArray = [prama allKeys];
     NSArray * sortArray = [keyArray sortedArrayUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
         return [obj1 compare:obj2 options:NSLiteralSearch];

     }];
  • 字典排序完畢,我們要進行組合,并對其采用URL編碼:
 NSMutableString * appendString = [NSMutableString string];

     [appendString appendString:@"GET&"];
     [appendString appendString:[self encodeToPercentEscapeString:baseUrl]];

     [appendString appendString:@"&"];
     NSMutableArray * tempArray = [NSMutableArray array];

     for (NSString * keys in sortArray) {
         [tempArray addObject:[NSString stringWithFormat:@"%@=%@",[self encodeToPercentEscapeString:keys],[self encodeToPercentEscapeString:prama[keys]]]];
     }
    NSString * comments  =  [tempArray componentsJoinedByString:@"&"];
     
     NSLog(@"com = %@",comments);
     [appendString appendString:[self encodeToPercentEscapeString:comments]];
  • 下面進行HMAC-SHA1簽名:
NSString * macsha = [self.class hmac_sha1:@"申請應(yīng)用所獲得consumer_secret&" text:appendString];
 NSString * praurl = [NSString stringWithFormat:@"oauth_signature=%@&oauth_consumer_key=%@&oauth_nonce=%@&oauth_signature_method=%@&oauth_timestamp=%@&oauth_version=%@",[self encodeToPercentEscapeString:macsha],prama[@"oauth_consumer_key"],prama[@"oauth_nonce"],prama[@"oauth_signature_method"],prama[@"oauth_timestamp"],prama[@"oauth_version"]];
//     NSLog(@"prama = %@",praurl);
NSString * replceurl = [NSString stringWithFormat:@"%@?%@",baseUrl,praurl];
  • 簽名組合完畢,進行如下請求驗證獲取第一次的Token:
 NSURL * url = [NSURL URLWithString:replceurl];
     NSLog(@"url = %@",url);

     NSMutableURLRequest * requestUrl = [NSMutableURLRequest requestWithURL:url];
     [requestUrl setHTTPMethod:@"GET"];
     NSURLSessionConfiguration * config = [NSURLSessionConfiguration defaultSessionConfiguration];
     NSURLSession * session = [NSURLSession sessionWithConfiguration:config delegate:nil delegateQueue:nil];

     NSURLSessionDataTask * task = [session dataTaskWithRequest:requestUrl completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
         if (data) {
             NSLog(@"有數(shù)據(jù)");
             NSString * string = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
             NSLog(@"string1 = %@",string);
         }else{
             NSString * string = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
             NSLog(@"string2 = %@",string);

         }
         NSLog(@"responce = %d",[(NSHTTPURLResponse *)response statusCode]);

         if (error) {
             NSLog(@"error = %@",[error localizedFailureReason]);
         }

     }];
     [task resume];

如果在請求中返回如下 code :

配置正確的情況下會出現(xiàn) 401 簽名的問題

如圖,選中的部分基本上是簽名錯誤會返回的,這個問題看著很簡單,因為如果不是按照規(guī)定的編碼順序,這個問題或者你要看上一天兩天了,我在幫他調(diào)試的時候,最后一步的因為一個參數(shù)未編碼,導(dǎo)致多浪費了半天時間,真的是自己挖坑哦。

總結(jié):

以上是快盤接入APP進行的一個簽名授權(quán)驗證, 后續(xù)一直按照如上方法,一直到獲取到accessToken 為止,如果還有不明白的,請留言!
如果以上有寫錯的地方,還望指出,給一些需要的人一些幫助。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容