1. 程式人生 > 其它 >ABAP呼叫阿里雲介面-簡訊服務-HTTP協議及簽名(abap版本)

ABAP呼叫阿里雲介面-簡訊服務-HTTP協議及簽名(abap版本)

技術標籤:介面SAPsapabap

阿里雲介面文件請參考官網地址

https://help.aliyun.com/document_detail/56189.html?spm=a2c4g.11186623.6.669.65fe7e6aztgHDF

此處僅介紹使用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 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.

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 ).