原文链接: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编码后的字符为小写,不符合当前要求,另外编码规则的不同点暂时发现的为"(“,”)“,“+”,“*”。
DATA: lv_char_str TYPE char1024,
lt_result TYPE match_result_tab,
ls_result TYPE match_result.
" url encodeing
lv_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.
"接口参数地址:https://next.api.aliyun.com/document/Dysmsapi/2017-05-25/SendBatchSms
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 = '2.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. 构造待签名的请求串
"签名说明:https://help.aliyun.com/document_detail/469176.html?spm=api-workbench.Troubleshoot.0.0.63e271851s3V0z
" 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 ).