原文链接:https://blog.csdn.net/xiefireworks/article/details/113037650
阿里云接口文档请参考官网地址
https://help.aliyun.com/document_detail/59210.html?spm=5176.8195934.J_5834642020.5.11ba4378DLVi4O
此处仅介绍使用ABAP完成阿里云短信服务签名请求的完成。
第一步:请求参数
1 abap 生成的uuid为32位不带“-”
2 特殊格式时间戳需要拼接
CONSTANTS: c_accesssecret TYPE string VALUE 'testSecret&',c_accesskeyid TYPE string VALUE 'testId'.*& 1. 填充参数
" 1.1 系统参数
GET TIME STAMP FIELD lv_timestampsap.
WRITE lv_timestampsap TO lv_timestampjava USING EDIT MASK lv_timestampformat TIME ZONE '0'.
TRY .lv_uuid = cl_system_uuid=>create_uuid_c32_static( ).CATCH cx_uuid_error.
ENDTRY.
APPEND VALUE #( key = 'SignatureMethod' value = 'HMAC-SHA1' ) TO lt_parameter.
APPEND VALUE #( key = 'SignatureNonce' value = lv_uuid ) TO lt_parameter.
APPEND VALUE #( key = 'AccessKeyId' value = c_accesskeyid ) TO lt_parameter.
APPEND VALUE #( key = 'SignatureVersion' value = '1.0' ) TO lt_parameter.
APPEND VALUE #( key = 'Timestamp' value = lv_timestampjava ) TO lt_parameter.
" 1.2 业务参数
APPEND VALUE #( key = 'Action' value = 'SendSms' ) TO lt_parameter.
APPEND VALUE #( key = 'Version' value = '2017-05-25' ) TO lt_parameter.
APPEND VALUE #( key = 'RegionId' value = 'cn-hangzhou' ) TO lt_parameter.
APPEND VALUE #( key = 'PhoneNumbers' value = '15300000001' ) TO lt_parameter.
APPEND VALUE #( key = 'SignName' value = '阿里云短信测试专用') TO lt_parameter.
APPEND VALUE #( key = 'TemplateParam' value = '{"customer":"test"}' ) TO lt_parameter.
APPEND VALUE #( key = 'TemplateCode' value = 'SMS_71390007' ) TO lt_parameter.
第二步:根据参数Key排序(顺序)
" 2.1 根据参数Key排序(顺序)
SORT lt_parameter BY key.
第三步:构造待签名的请求串
1 sap自带的escape function 含pop特殊规则,不用再做替换
" 2.2 拼接URL编码后的参数值
LOOP AT lt_parameter INTO ls_parameter.lv_sortquerystring_temp = lv_sortquerystring_temp && '&' && escape( val = ls_parameter-key format = cl_abap_format=>e_uri_full )&& '=' && escape( val = ls_parameter-value format = cl_abap_format=>e_uri_full ).
ENDLOOP.
" 2.3 特殊URL编码 POP特殊的一种规则,即在一般的URLEncode后再增加三种字符替换
"使用escap format cl_abap_format=>e_uri_full 时满足最终条件不用如下转换
*REPLACE ALL OCCURRENCES OF '+' IN lv_sortquerystring_temp WITH '%20'.
*REPLACE ALL OCCURRENCES OF '*' IN lv_sortquerystring_temp WITH '%2A'.
*REPLACE ALL OCCURRENCES OF '%7E' IN lv_sortquerystring_temp WITH '~'.
lv_sortquerystring = lv_sortquerystring_temp.
SHIFT lv_sortquerystring LEFT DELETING LEADING '&'."移除第一个&" 2.4. 按POP的签名规则拼接成最终的待签名串
lv_sortquerystring = 'GET' && '&' && escape( val = '/' format = cl_abap_format=>e_uri_full ) && '&'&& escape( val = lv_sortquerystring format = cl_abap_format=>e_uri_full ) .
第四步:签名
1 签名使用HmacSHA1算法 返回的Base64加密字符串,并作url编码
" 3.1 设置签名 key
lo_cl_abap_hmac = cl_abap_hmac=>get_instance( if_key = cl_abap_hmac=>string_to_xstring( if_input = c_accesssecret ) ).
" 3.2 生成签名
" 3.2 生成签名
TRY.lo_cl_abap_hmac->final( EXPORTING if_data = cl_abap_hmac=>string_to_xstring( if_input = lv_sortquerystring )IMPORTING ef_hmacb64string = lv_signature ) .CATCH cx_abap_message_digest .
ENDTRY.
" 3.2 最终生成的签名也要做特殊URL编码
lv_signature = escape( val = lv_signature format = cl_abap_format=>e_uri_full ).
第五步:增加签名结果到请求参数中,发送请求。
*& 4. 生成最终请求url
lv_url = 'http://dysmsapi.aliyuncs.com/?Signature=' && lv_signature && lv_sortquerystring_temp.DATA: lv_out_put TYPE string.
lv_out_put = lv_out_put && 'SignatureNonce:' && cl_bcs_convert=>gc_crlf && lv_uuid && cl_bcs_convert=>gc_crlf.
lv_out_put = lv_out_put && 'Timestamp:' && cl_bcs_convert=>gc_crlf && lv_timestampjava && cl_bcs_convert=>gc_crlf.
lv_out_put = lv_out_put && 'sortedQueryString:' && cl_bcs_convert=>gc_crlf && lv_sortquerystring && cl_bcs_convert=>gc_crlf.
lv_out_put = lv_out_put && 'signature:' && cl_bcs_convert=>gc_crlf && lv_signature && cl_bcs_convert=>gc_crlf.
lv_out_put = lv_out_put && 'URL:' && cl_bcs_convert=>gc_crlf && lv_url && cl_bcs_convert=>gc_crlf.cl_demo_text=>display_string( lv_out_put ).
ps:
1.使用function escape 可以使用不同的format, cl_abap_format=>e_uri_full 符合要求的,同样还有其它格式如cl_abap_format=>e_url_full和java示例中的url 编码效果一致,需要再做pop特殊替换
2.如果没有function escape,可以使用方法cl_http_utility=>if_http_utility~escape_url,问题是该方法url编码后的字符为小写,不符合当前要求,另外编码规则的不同点暂时发现的为"(“,”)“,“+”,“*”。
3.暂留后续封装
DATA: lv_char_str TYPE char1024,lt_result TYPE match_result_tab,ls_result TYPE match_result." url encodeinglv_char_str = cl_http_utility=>if_http_utility~escape_url( iv_urlstring ).FIND ALL OCCURRENCES OF REGEX '%..' IN lv_char_str RESULTS lt_result.LOOP AT lt_result INTO ls_result.TRANSLATE lv_char_str+ls_result-offset(ls_result-length) TO UPPER CASE.ENDLOOP."该方法不会转换()REPLACE ALL OCCURRENCES OF '(' IN lv_char_str WITH '%28'.REPLACE ALL OCCURRENCES OF ')' IN lv_char_str WITH '%29'." 特殊URL编码 POP特殊的一种规则,即在一般的URLEncode后再增加三种字符替换
* REPLACE ALL OCCURRENCES OF '+' IN lv_char_str WITH '%20'.
* REPLACE ALL OCCURRENCES OF '*' IN lv_char_str WITH '%2A'.REPLACE ALL OCCURRENCES OF '%7E' IN lv_char_str WITH '~'.
附加完整的Java签名Demo代码
TYPES: BEGIN OF ty_parameter,key TYPE string,value TYPE string,END OF ty_parameter.DATA: lo_cl_abap_hmac TYPE REF TO cl_abap_hmac.DATA: lv_signature TYPE string,lv_sortquerystring TYPE string,lv_sortquerystring_temp TYPE string.DATA: lt_parameter TYPE TABLE OF ty_parameter,ls_parameter TYPE ty_parameter.DATA: lv_timestampsap TYPE timestamp,lv_timestampformat TYPE char30 VALUE '____-__-__T__:__:__Z',lv_timestampjava TYPE char30,lv_uuid TYPE char36.DATA: lv_url TYPE string.CONSTANTS: c_accesssecret TYPE string VALUE 'testSecret&',c_accesskeyid TYPE string VALUE 'testId'.*& 1. 填充参数
" 1.1 系统参数
GET TIME STAMP FIELD lv_timestampsap.
WRITE lv_timestampsap TO lv_timestampjava USING EDIT MASK lv_timestampformat TIME ZONE '0'.
TRY .lv_uuid = cl_system_uuid=>create_uuid_c32_static( ).CATCH cx_uuid_error.
ENDTRY.
APPEND VALUE #( key = 'SignatureMethod' value = 'HMAC-SHA1' ) TO lt_parameter.
APPEND VALUE #( key = 'SignatureNonce' value = lv_uuid ) TO lt_parameter.
APPEND VALUE #( key = 'AccessKeyId' value = c_accesskeyid ) TO lt_parameter.
APPEND VALUE #( key = 'SignatureVersion' value = '1.0' ) TO lt_parameter.
APPEND VALUE #( key = 'Timestamp' value = lv_timestampjava ) TO lt_parameter.
" 1.2 业务参数
APPEND VALUE #( key = 'Action' value = 'SendSms' ) TO lt_parameter.
APPEND VALUE #( key = 'Version' value = '2017-05-25' ) TO lt_parameter.
APPEND VALUE #( key = 'RegionId' value = 'cn-hangzhou' ) TO lt_parameter.
APPEND VALUE #( key = 'PhoneNumbers' value = '15300000001' ) TO lt_parameter.
APPEND VALUE #( key = 'SignName' value = '阿里云短信测试专用' ) TO lt_parameter.
APPEND VALUE #( key = 'TemplateParam' value = '{"customer":"test"}') TO lt_parameter.
APPEND VALUE #( key = 'TemplateCode' value = 'SMS_71390007' ) TO lt_parameter.*& 2. 构造待签名的请求串" 2.1 根据参数Key排序(顺序)
SORT lt_parameter BY key.
" 2.2 拼接URL编码后的参数值
LOOP AT lt_parameter INTO ls_parameter.lv_sortquerystring_temp = lv_sortquerystring_temp && '&' && escape( val = ls_parameter-key format = cl_abap_format=>e_uri_full )&& '=' && escape( val = ls_parameter-value format = cl_abap_format=>e_uri_full ).
ENDLOOP." 2.3 特殊URL编码 POP特殊的一种规则,即在一般的URLEncode后再增加三种字符替换
"使用escap format cl_abap_format=>e_uri_full 时满足最终条件不用如下转换
*REPLACE ALL OCCURRENCES OF '+' IN lv_sortquerystring_temp WITH '%20'.
*REPLACE ALL OCCURRENCES OF '*' IN lv_sortquerystring_temp WITH '%2A'.
*REPLACE ALL OCCURRENCES OF '%7E' IN lv_sortquerystring_temp WITH '~'.lv_sortquerystring = lv_sortquerystring_temp.
SHIFT lv_sortquerystring LEFT DELETING LEADING '&'."移除第一个&
" 2.4. 按POP的签名规则拼接成最终的待签名串
lv_sortquerystring = 'GET' && '&' && escape( val = '/' format = cl_abap_format=>e_uri_full ) && '&'&& escape( val = lv_sortquerystring format = cl_abap_format=>e_uri_full ) .*& 3. 生成签名
" 3.1 设置签名 key
lo_cl_abap_hmac = cl_abap_hmac=>get_instance( if_key = cl_abap_hmac=>string_to_xstring( if_input = c_accesssecret ) ).
" 3.2 生成签名
" 3.2 生成签名
TRY.lo_cl_abap_hmac->final( EXPORTING if_data = cl_abap_hmac=>string_to_xstring( if_input = lv_sortquerystring )IMPORTING ef_hmacb64string = lv_signature ) .CATCH cx_abap_message_digest .
ENDTRY.
" 3.2 最终生成的签名也要做特殊URL编码
lv_signature = escape( val = lv_signature format = cl_abap_format=>e_uri_full ).*& 4. 生成最终请求url
lv_url = 'http://dysmsapi.aliyuncs.com/?Signature=' && lv_signature && lv_sortquerystring_temp.DATA: lv_out_put TYPE string.
lv_out_put = lv_out_put && 'SignatureNonce:' && cl_bcs_convert=>gc_crlf && lv_uuid && cl_bcs_convert=>gc_crlf.
lv_out_put = lv_out_put && 'Timestamp:' && cl_bcs_convert=>gc_crlf && lv_timestampjava && cl_bcs_convert=>gc_crlf.
lv_out_put = lv_out_put && 'sortedQueryString:' && cl_bcs_convert=>gc_crlf && lv_sortquerystring && cl_bcs_convert=>gc_crlf.
lv_out_put = lv_out_put && 'signature:' && cl_bcs_convert=>gc_crlf && lv_signature && cl_bcs_convert=>gc_crlf.
lv_out_put = lv_out_put && 'URL:' && cl_bcs_convert=>gc_crlf && lv_url && cl_bcs_convert=>gc_crlf.cl_demo_text=>display_string( lv_out_put ).