iOS SDK提供了STS鑒權模式、自簽名模式以及URL簽名的方式來保障移動終端的安全性。
注意事項
無論是STS鑒權模式還是自簽名模式,您實現的回調函數都需要保證調用時Token、Signature的返回結果。如果您需要實現向業務Server獲取Token、Signature的網絡請求,建議調用網絡庫的同步接口。回調都是在SDK發起具體請求時,在請求的子線程中執行,所以不會阻塞主線程。
STS鑒權模式
通過STS臨時授權訪問OSS的步驟如下:
獲取臨時訪問憑證
臨時訪問憑證包括臨時訪問密鑰(AccessKey ID和AccessKey Secret)和安全令牌(SecurityToken)。臨時訪問憑證有效時間單位為秒,最小值為900,最大值以當前角色設定的最大會話時間為準。更多信息,請參見設置RAM角色最大會話時間。
您可以通過以下兩種方式獲取臨時訪問憑證。
方式一
通過調用STS服務的AssumeRole接口獲取臨時訪問憑證。
方式二
通過各語言STS SDK獲取臨時訪問憑證。
使用臨時訪問憑證初始化SDK
id<OSSCredentialProvider> credential = [[OSSStsTokenCredentialProvider alloc] initWithAccessKeyId:@"<StsToken.AccessKeyId>" secretKeyId:@"<StsToken.SecretKeyId>" securityToken:@"<StsToken.SecurityToken>"]; client = [[OSSClient alloc] initWithEndpoint:endpoint credentialProvider:credential];
說明如果您需要使用OSSAuthCredentialProvider初始化SDK,請參見初始化。
通過臨時訪問憑證初始化SDK時,需要注意StsToken的有效時間。以下代碼用于判斷StsToken的有效時間:
NSDateFormatter * fm = [NSDateFormatter new]; fm.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]; [fm setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZ"]; NSDate *expirationDate = [fm dateFromString:@"<StsToken.Expiration>"]; NSTimeInterval interval = [expirationDate timeIntervalSinceDate:[NSDate date]]; // 即將過期,有效時間小于5分鐘。 if (interval < 5 * 60) { id<OSSCredentialProvider> credential = [[OSSStsTokenCredentialProvider alloc] initWithAccessKeyId:@"<StsToken.AccessKeyId>" secretKeyId:@"<StsToken.SecretKeyId>" securityToken:@"<StsToken.SecurityToken>"]; client = [[OSSClient alloc] initWithEndpoint:endpoint credentialProvider:credential]; }
手動更新StsToken
當判斷StsToken即將過期時,您可以重新構造OSSClient,也可以通過如下方式更新CredentialProvider。
id<OSSCredentialProvider> credential = [[OSSStsTokenCredentialProvider alloc] initWithAccessKeyId:@"<StsToken.AccessKeyId>" secretKeyId:@"<StsToken.SecretKeyId>" securityToken:@"<StsToken.SecurityToken>"]; client = [[OSSClient alloc] initWithEndpoint:endpoint credentialProvider:credential];
自動更新StsToken
如果您期望SDK自動更新StsToken,那么您需要在SDK的應用中實現回調。通過您實現回調的方式去獲取Federation Token(即StsToken),SDK會使用此StsToken來進行加簽處理,并在需要更新時主動調用此回調來獲取StsToken。
id<OSSCredentialProvider> credential = [[OSSFederationCredentialProvider alloc] initWithFederationTokenGetter:^OSSFederationToken * { // 您需要在此處實現獲取一個FederationToken,并構造成OSSFederationToken對象返回。 // 如果由于某種原因獲取失敗,直接返回nil。 OSSFederationToken * token; // 從您的服務器中獲取token。 ... return token; }]; client = [[OSSClient alloc] initWithEndpoint:endpoint credentialProvider:credential];
說明如果您已經通過其他方式獲取了StsToken所需的各個字段,也可以在回調中直接返回StsToken。但您需要手動處理StsToken的更新,且更新后重新設置該OSSClient實例的OSSCredentialProvider。
假設您訪問的Server地址為http://localhost:8080/distribute-token.json,則返回的數據如下:
{ "StatusCode": 200, "AccessKeyId":"STS.iA645eTOXEqP3cg3****", "AccessKeySecret":"rV3VQrpFQ4BsyHSAvi5NVLpPIVffDJv4LojU****", "Expiration":"2015-11-03T09:52:59Z", "SecurityToken":"CAES7QIIARKAAZPlqaN9ILiQZPS+JDkS/GSZN45RLx4YS/p3OgaUC+oJl3XSlbJ7StKpQ****" }
實現OSSFederationCredentialProvider的示例如下。
id<OSSCredentialProvider> credential2 = [[OSSFederationCredentialProvider alloc] initWithFederationTokenGetter:^OSSFederationToken * { // 構造請求訪問您的業務Server。 NSURL * url = [NSURL URLWithString:@"http://localhost:8080/distribute-token.json"]; // 通過request設置自有服務器需要的參數。 NSURLRequest * request = [NSURLRequest requestWithURL:url]; OSSTaskCompletionSource * tcs = [OSSTaskCompletionSource taskCompletionSource]; NSURLSession * session = [NSURLSession sharedSession]; // 發送請求。 NSURLSessionTask * sessionTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (error) { [tcs setError:error]; return; } [tcs setResult:data]; }]; [sessionTask resume]; // 需要阻塞等待請求返回。 [tcs.task waitUntilFinished]; // 解析結果。 if (tcs.task.error) { NSLog(@"get token error: %@", tcs.task.error); return nil; } else { // 返回數據為JSON格式,需要解析返回數據得到token的各個字段。 NSDictionary * object = [NSJSONSerialization JSONObjectWithData:tcs.task.result options:kNilOptions error:nil]; OSSFederationToken * token = [OSSFederationToken new]; token.tAccessKey = [object objectForKey:@"AccessKeyId"]; token.tSecretKey = [object objectForKey:@"AccessKeySecret"]; token.tToken = [object objectForKey:@"SecurityToken"]; token.expirationTimeInGMTFormat = [object objectForKey:@"Expiration"]; NSLog(@"get token: %@", token); return token; } }];
簽名URL
注意事項
生成簽名URL過程中,SDK利用本地存儲的密鑰信息,根據特定算法計算出簽名(signature),然后將其附加到URL上,以確保URL的有效性和安全性。這一系列計算和構造URL的操作都是在客戶端完成,不涉及網絡請求到服務端。因此,生成簽名URL時不需要授予調用者特定權限。但是,為避免第三方用戶無法對簽名URL授權的資源執行相關操作,需要確保調用生成簽名URL接口的身份主體被授予對應的權限。
例如,通過簽名URL上傳文件時,需要授予oss:PutObject權限。通過簽名URL下載或預覽文件時,需要授予oss:GetObject權限。
通過以下示例生成的簽名URL中如果包含特殊符號
+
,可能出現無法正常訪問該簽名URL的現象。如需正常訪問該簽名URL,請將簽名URL中的+
替換為%2B
。
使用簽名URL上傳文件
生成用于上傳文件的簽名URL。
// 填寫Bucket名稱。 NSString *bucketName = @"examplebucket"; // 填寫Object名稱。 NSString *objectKey = @"exampleobject.txt"; NSURL *file = [NSURL fileURLWithPath:@"<filePath>"]; NSString *contentType = [OSSUtil detemineMimeTypeForFilePath:file.absoluteString uploadName:objectKey]; __block NSString *urlString; // 生成用于上傳的簽名URL,并指定簽名URL過期時間為30分鐘。 OSSTask *task = [client presignConstrainURLWithBucketName:bucketName withObjectKey:objectKey httpMethod:@"PUT" withExpirationInterval:30 * 60 withParameters:@{} contentType:contentType contentMd5:nil]; [task continueWithBlock:^id _Nullable(OSSTask * _Nonnull task) { if (task.error) { NSLog(@"presign error: %@", task.error); } else { urlString = task.result; NSLog(@"url: %@", urlString); } return nil; }];
使用簽名URL上傳文件。
// 通過簽名URL上傳文件。 NSURL * url = [NSURL URLWithString:urlString]; NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:url]; request.HTTPMethod = @"PUT"; request.allHTTPHeaderFields = @{OSSHttpHeaderContentType: contentType}; NSURLSession * session = [NSURLSession sharedSession]; NSURLSessionTask * sessionTask = [session uploadTaskWithRequest:request fromFile:file completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { if (error) { NSLog(@"upload error: %@", error); return; } else if (((NSHTTPURLResponse*)response).statusCode == 203 || ((NSHTTPURLResponse*)response).statusCode >= 300) { NSString *body = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"upload error: %@", body); return; } NSLog(@"upload success"); }]; [sessionTask resume];
使用簽名URL下載文件
生成用于下載文件的簽名URL。
// 填寫Bucket名稱。 NSString *bucketName = @"examplebucket"; // 填寫Object名稱。 NSString *objectKey = @"exampleobject.txt"; __block NSString *urlString; // 生成用于下載的簽名URL,并指定簽名URL過期時間為30分鐘。 OSSTask *task = [client presignConstrainURLWithBucketName:bucketName withObjectKey:objectKey httpMethod:@"GET" withExpirationInterval:30 * 60 withParameters:@{}]; [task continueWithBlock:^id _Nullable(OSSTask * _Nonnull task) { if (task.error) { NSLog(@"presign error: %@", task.error); } else { urlString = task.result; NSLog(@"url: %@", urlString); } return nil; }];
使用簽名URL下載文件。
// 使用簽名URL下載文件。 NSURL * url = [NSURL URLWithString:urlString]; NSURLRequest * request = [NSURLRequest requestWithURL:url]; NSURLSession * session = [NSURLSession sharedSession]; NSURLSessionTask * sessionTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { if (error) { NSLog(@"download error: %@", error); return; } else if (((NSHTTPURLResponse*)response).statusCode == 203 || ((NSHTTPURLResponse*)response).statusCode >= 300) { NSString *body = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"download error: %@", body); return; } NSLog(@"download success"); }]; [sessionTask resume];