Delphi开发阿里短信接口

系统需要试用阿里短信接口发送多可文档系统短信通知,但阿里没有提供DELPHI代码示例。在构造签名字符串时遇到了编码和签名几个坑,经过努力解决了签名问题,如下代码给大家参考:
相关代码需要包含的头如下:

 IdURI, IdGlobal, IdUriUtils, IdHMACSHA1, IdCoderMIME 
// URL编码函数,阿里提供的JAVA是  java.net.URLEncoder.encode(value, "UTF-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~");
function SpecialUrlEncode(const ASrc: string; AByteEncoding: IIdTextEncoding = nil): string;
const
    UnsafeChars = '&=*<>#%"{}|\^[]`:';
var
    I, J, CharLen, ByteLen: Integer;
    Buf: TIdBytes;
    LChar: WideChar;

begin
    Result := '';
    Buf := nil;
    if ASrc = '' then begin
        Exit;
    end;
    EnsureEncoding(AByteEncoding, encUTF8);
    SetLength(Buf, AByteEncoding.GetMaxByteCount(2));

    I := 0;
    while I < Length(ASrc) do begin
        LChar := ASrc[I + 1];
        if LChar = '+' then begin
            Result := Result + '%20';
            Inc(I);

        end
        else if WideCharIsInSet(UnsafeChars, LChar) or (Ord(LChar) < 33) or (Ord(LChar) > 127) then
        begin
            CharLen := CalcUTF16CharLength(ASrc, I + 1);
            ByteLen := AByteEncoding.GetBytes(ASrc, I + 1, CharLen, Buf, 0);
            for J := 0 to ByteLen - 1 do begin
                Result := Result + '%' + IntToHex(Ord(Buf[J]), 2);
            end;
            Inc(I, CharLen);
        end
        else begin
            Result := Result + Char(LChar);
            Inc(I);
        end;
    end;
    //
    Result := StringReplace(Result, '%7E', '~', [rfReplaceAll, rfIgnoreCase]);
end;

// HA1 签名
function HMACSHA1(const AData, AKey: string): string;
var
    LHMACSHA1: TIdHMACSHA1;
begin
    LHMACSHA1 := TIdHMACSHA1.Create;
    try
        LHMACSHA1.Key := ToBytes(AKey);
        Result := TIdEncoderMIME.EncodeBytes(LHMACSHA1.HashValue(ToBytes(AData)));
    finally
        LHMACSHA1.Free;
    end;
end;

//
function LocalTimeZoneBias(): Integer;
var
    TimeZoneInformation: TTimeZoneInformation;
    Bias: Longint;
begin
    case GetTimeZoneInformation(TimeZoneInformation) of
        TIME_ZONE_ID_STANDARD:
            Bias := TimeZoneInformation.Bias + TimeZoneInformation.StandardBias;
        TIME_ZONE_ID_DAYLIGHT:
            Bias := TimeZoneInformation.Bias + ((TimeZoneInformation.DaylightBias div 60) * -100);
    else
        Bias := TimeZoneInformation.Bias;
    end;
    Result := Bias;
end;

//GMT格式日期
function DateTimeToGMT(const DT: TDateTime): TDateTime;
begin
    Result := DT + LocalTimeZoneBias() / 1440;
end;

(*
  //阿里提供的JAVA示例

  public static String sign(String accessSecret, String stringToSign) throws Exception {
  javax.crypto.Mac mac = javax.crypto.Mac.getInstance("HmacSHA1");
  mac.init(new javax.crypto.spec.SecretKeySpec(accessSecret.getBytes("UTF-8"), "HmacSHA1"));
  byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
  return new sun.misc.BASE64Encoder().encode(signData);
  }
*)

// 阿里的示例签名字符串
// GET&%2F&AccessKeyId%3DtestId%26Action%3DSendSms%26Format%3DXML%26OutId%3D123%26PhoneNumbers%3D15300000001%26RegionId%3Dcn-hangzhou%26SignName%3D%25E9%2598%25BF%25E9%2587%258C%25E4%25BA%2591%25E7%259F%25AD%25E4%25BF%25A1%25E6%25B5%258B%25E8%25AF%2595%25E4%25B8%2593%25E7%2594%25A8%26SignatureMethod%3DHMAC-SHA1%26SignatureNonce%3D45e25e9b-0a6f-4070-8c85-2956eda1b466%26SignatureVersion%3D1.0%26TemplateCode%3DSMS_71390007%26TemplateParam%3D%257B%2522customer%2522%253A%2522test%2522%257D%26Timestamp%3D2017-07-12T02%253A42%253A19Z%26Version%3D2017-05-25
// 签名结果为 zJDF+Lrzhj/ThnlvIToysFRq6t4=


// 构造待签名的请求串
function AliyunSignatureUrl(Mobile, TemplateId, TemplateParam, SignName, AccessKeyId, AccessKeySecret: string): string;
var
    List: TStringList;
    Df, Nonce, Ks, Sign: string;
    I: Integer;
    DT: TDateTime;
    GUID: TGUID;
begin
    CreateGuid(GUID);
    Nonce := GUIDtoString(GUID);
    Nonce := Copy(Nonce, 2, Length(Nonce) - 2);
    //
    DT := DateTimeToGMT(Now()); // 把本地时间转化为 GMT 时间
    Df := FormatDateTime('yyyy-MM-dd', DT) + 'T' + FormatDateTime('HH:mm:ss', DT) + 'Z';
    //
    List := TStringList.Create();
    try
        // 短信参数
        List.Append('PhoneNumbers=' + Mobile);
        List.Append('SignName=' + SignName);
        List.Append('TemplateCode=' + TemplateId);
        List.Append('TemplateParam=' + TemplateParam);
        List.Append('OutId=test-001');

        // 公共请求参数
        List.Append('AccessKeyId=' + AccessKeyId);
        List.Append('Action=SendSms');
        List.Append('Format=JSON');
        List.Append('RegionId=cn-hangzhou');
        List.Append('SignatureMethod=HMAC-SHA1');
        List.Append('SignatureNonce=' + Nonce);
        List.Append('SignatureVersion=1.0');
        List.Append('Timestamp=' + Df);
        List.Append('Version=2017-05-25');

        // 参数Key排序
        List.UseLocale := False;
        List.CaseSensitive := True;
        List.Sorted := True;

        //
        Ks := '';
        for I := 0 to List.Count - 1 do begin
            if I > 0 then
                Ks := Ks + '&';
            Ks := Ks + SpecialUrlEncode(List.Names[I]) + '=' + SpecialUrlEncode(List.ValueFromIndex[I]);
        end;

        // 数字签名
        Sign := HMACSHA1('GET&%2F&' + SpecialUrlEncode(Ks), AccessKeySecret + '&');
        Sign := SpecialUrlEncode(Sign);
        //
        Result := '?Signature=' + Sign + '&' + Ks;
    finally
        List.Free();
    end;
end;

最后调用示例:

//手机号, 模板ID, 模板参数, 签名名称, 阿里短信AccessKeyId, 阿里短信AccessKeySecret
AliyunSignatureUrl('1390010001', 'Sms001999', '多可文档管理系统短信模板', '多可文档管理系统', 'AccessKeyId', 'AccessKeySecret');

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值