ali-oss 签名经常不对,特此记录一下,下面的代码是flutter的,原理是一样的。主要是签名message的拼接方式,特别容易错还不容易校验。
1. PubObject 文件上传 文档链接
import 'dart:convert';
import 'dart:io';
import 'package:crypto/crypto.dart';
import 'package:dio/dio.dart';
import 'package:flutter_network/flutter_network.dart';
import 'package:flutter_oss/src/constance.dart';
import 'package:flutter_oss/src/oss_model.dart';
import 'package:intl/intl.dart';
import 'package:intl/date_symbol_data_local.dart';
import 'package:mime/mime.dart';
typedef SendProgress = Function(int send, int total);
class UploadOSS {
static Future<String> upload(
{required File file,
required String bucket,
required String regionId,
required String destinePath,
required TicketModel ticketModel,
SendProgress? onSendProgress}) async {
try {
var verb = "PUT";
var contentMd5 = "";
var contentType = lookupMimeType(file.path);
var date = requestTime();
var canonicalizedOSSHeaders =
"x-oss-security-token:" + ticketModel.securityToken! + "\n";
var canonicalizedResource = "/" + bucket + "/" + destinePath;
var message = '''$verb
$contentMd5
$contentType
$date
$canonicalizedOSSHeaders$canonicalizedResource''';
/*
测试数据
var message = "PUT
text/plain
Fri, 23 Sep 2022 10:17:14 GMT
x-oss-security-token:CAISqAJ1q6Ft5B2yfSjIr5fzEszWn7h4gaSDekncs0YmdOtclpXtlzz2IHlLfnZuA+oYt/w+mGxY6fsflqMpFs5tS1OBZNNotgTdFZV8O9ivgde8yJBZonfMewHKeQuZsebWZ+LmNpy/Ht6md1HDkAJq3LL+bk/Mdle5MJqP+/kFC9MMRVuAcCZhDtVbLRcYi618D3bKMuu3ORPHm3fZCFES2jBxkmRi86+ysIr+rxPVlw/90fRH5dazcJK+ZshqN5A6WNCw2etwM7Lc2ipR4F9X76psl+sepGaA/PPlWggMs07farCLo4A2dlMoOZJXQfAU8KLO8tRjofHWmojNzBJAAPpYSSy3Rvr7mZSeR73zbIhgLeenZySSj42VWIP8tgQ/emLCy9ijvRD0QRqAARfutxqmwUeuT/zdLXzswFDDtAj7255Cw50XXesX2mUwzGGfP/hEz+7Fh8vjsRAnp56DwfEN/Ph8hpwY+Rui3XtEvxDKe27GE+yH0zgKldi2Kh1eam8sdiNVCUqMyzTYhqg8tQsiTt3suQrrLEuyZylKz5UVEfNrf/ygoRGnF/lq
/brainco-common-public/users/259/dev/test_files/1663928233935-1392323866593.txt"
var signature =
var signature = UploadOSS.getSignature(message,"BKtAoNjTZ95WqUhHC8HopovJbmRKKotPZHneLHG3SNrJ");
signature 应该是: gg4uLupC6MqgAOiC+dPq8qAGMB8=
*/
var signature = getSignature(message, ticketModel.accessKeySecret!);
var authorization = "OSS " + ticketModel.accessKeyId! + ":" + signature;
//bucket xxxx-common-public
var url = 'https://$bucket.oss-$regionId.aliyuncs.com/$destinePath';
//https://xxxx-common-public.oss-cn-hangzhou.aliyuncs.com/test-1.png
var length = file.lengthSync();
//速度快 有进度
Stream<List<int>> stream =
MultipartFile.fromFileSync(file.path).finalize();
var response = await FocusHttpUtil(tag: kDioTag).rest.put(url,
data: stream,
onSendProgress: onSendProgress,
options: Options(headers: {
'authorization': authorization,
'content-Type': contentType,
'date': date,
'x-oss-security-token': ticketModel.securityToken,
'Content-Length': length
}));
if (response.statusCode == 200) {
return url;
}
throw response.toString();
// 成功后返回文件访问路径
} catch (e) {
throw e.toString();
}
}
/// 获取文件类型
static String getFileType(String path) {
var array = path.split('.');
return array[array.length - 1];
}
/// 获取签名
static String getSignature(String policyText, String ossAccessKeySecret) {
final digest = Hmac(sha1, utf8.encode(ossAccessKeySecret))
.convert(utf8.encode(policyText));
return base64.encode(digest.bytes);
}
static String requestTime() {
initializeDateFormatting('en', null);
final DateTime now = DateTime.now();
final String string =
DateFormat('EEE, dd MMM yyyy HH:mm:ss', 'en_ISO').format(now.toUtc());
return '$string GMT';
}
}
私有文件访问 授权访问
注意:此处的签名和PubObject的message不一致
static Future<String> getAuthorityUrl(
{required String url, required String token}) async {
if (!url.contains('-private.')) {
return url;
}
var path = url.split('.aliyuncs.com/')[1];
RegExp exp = RegExp(r"\w+://(.*?).oss");
var bucket = exp.firstMatch(url)?.group(1);
RegExp exp2 = RegExp(r".+oss-(.*?).aliyuncs.com");
var regionId = exp2.firstMatch(url)?.group(1);
var ticketModel = await OSSApi.getReadTicket(bucket!, regionId!, token);
var verb = "GET";
var contentMd5 = "";
var contentType = "";
final DateTime now = DateTime.now().add(const Duration(hours: 1));
final expires = now.millisecondsSinceEpoch ~/ 1000;
var canonicalizedOSSHeaders =
"security-token=" + ticketModel.securityToken!;
var canonicalizedResource = "/" + bucket + "/" + path;
//特别注意
var message = """$verb
$contentMd5
$contentType
$expires
$canonicalizedResource?$canonicalizedOSSHeaders""";
/*
测试数据
var message = "GET
1663931316
/brainco-common-private/testfile/1.txt?security-token=CAISngJ1q6Ft5B2yfSjIr5f9fO38gugX8fuldUnGqjkNQehth5P+iDz2IHlLfnZuA+oYt/w+mGxY6fsflqMpFs5tS1OBZNNoth2qdJZ8O9ivgde8yJBZoozHcDHhF3yW9cvWZPqDA7G5U/yxalfCuzZuyL/hD1uLVECkNpv77vwCac8MDCa1cR1MBtpdOnFIyqkgOGDWKOymPzPzn2PUFzAIgAdnjn5l4qnNjK/Q4xHF3lrh0b1X9cajKIKtbs9nO9J0VNKw2+ozbrDAzidM5l8I1t8v3fEUom6e5I7MXgALv0TZCYeOrI0zdj0eT7MhBqtJoML7kfBFoeHJn+z1sU0UYrsKDX6FGtn4kZeYSLz0a8xXb7/+PG/Wwglw7XAzedZPGoABjJ8Gnx8H7Tpne0Akd3JFZx7E1rBtCDErKOF4H8HO0/bmZ+MiTaQmcxWiwUF8SSAYHetMhKcp0xoZZQUSx29AZvPmvsAHb660dXaTbriic+ncmMPsvt+tDrKz77xKe82xM39A806rGMoJC23bNepJ3fCaHN3Oy+cMBbhsFd1ViAw="
var signature =
var signature = UploadOSS.getSignature(message,"nZGCDZxRnp2KUrxAzvg1KicAFQqVPz3qbcdw6n5VCb2");
signature 应该是: wtE6jMCrgSxRY6FFrcYq/tCYwFA=
*/
var signature =
UploadOSS.getSignature(message, ticketModel.accessKeySecret!);
var result =
'OSSAccessKeyId=${ticketModel.accessKeyId}&Expires=$expires&Signature=${Uri.encodeQueryComponent(signature)}&security-token=${Uri.encodeQueryComponent(ticketModel.securityToken!)}';
return '$url?$result';
}