其他相關資料帖可參考:
https://blog.csdn.net/woniu_maggie/article/details/146210752
https://blog.csdn.net/SAPmatinal/article/details/134349125
https://blog.csdn.net/weixin_44382089/article/details/128283417
【業務場景】
外部系統不想通過RFC (需要安裝SAP官網的組件DDL等架包才能支持SAP 遠程RFC的JDBC訪問,比較麻煩)和WEBSERIVE服務方式訪問接口,可通過restful接口方式訪問更方便
1.SE24新建CLASS類:?ZCL_QUERY_GDDH_DATA
激活,然后添加interface接口:IF_HTTP_EXTENSION并激活。
2.實現IF_HTTP_EXTENSION~HANDLE_REQUEST
擴展方法IF_HTTP_EXTENSION~HANDLE_REQUEST, 可以根據GET/POST請求方式處理,這個接口采用的是POST請求方式
部分參數可以放到URL上面參數傳入,若有TOKEN認證放在REQUEST請求的BODY里面以json方式傳入,這個跟對方協商好就行,注意信息安全要求。
POST參數設置
?if_http_extension~handle_request.方法中獲取接口的調用方式是GET?/?POST請求
METHOD?if_http_extension~handle_request.
??"調用的方法?GET?/?POST
??DATA(lv_method)?=?server->request->get_method(?).
??CASE?lv_method.
????WHEN?'GET'.
??????me->get(?server?).
????WHEN?'POST'.
??????me->post(?server?).
??ENDCASE.
ENDMETHOD.?
GET請求方式:?
? METHOD?get.
????TYPES:
??????BEGIN?OF?ty_input,
????????token?TYPE?string,
??????END?OF?ty_input.
????DATA:?BEGIN?OF?ls_result,
????????????data????TYPE?STANDARD?TABLE?OF?ty_input,
????????????msg?????TYPE?string,
????????????success?TYPE?string,
??????????END?OF?ls_result.
????DATA:?lt_fields???????TYPE?tihttpnvp,
??????????ls_fields???????TYPE?ihttpnvp,
??????????lv_header_query?TYPE?string,
??????????lv_data?????????TYPE?string,
??????????lv_html?????????TYPE?string,
??????????lv_body?????????TYPE?string,
??????????lv_token????????TYPE?string,
??????????lv_content_type?TYPE?string,
??????????lv_md5??????????TYPE?string,
??????????lv_algo?????????TYPE?string,
??????????ls_info?????????TYPE?zshr_pernr_info_gddh,
??????????lv_zphone???????TYPE?zphone,
??????????lv_icnum????????TYPE?psg_idnum.
????FIELD-SYMBOLS:?<fs_field>?LIKE?LINE?OF?lt_fields.
????"Json結構
????DATA:?BEGIN?OF?ls_request,
????????????datalist?TYPE?TABLE?OF?zshr_pernr_info_gddh,
??????????END?OF?ls_request.
????"傳輸結構
????DATA:?ls_itab?TYPE?zshr_pernr_info_gddh,
??????????lt_itab?TYPE?TABLE?OF?zshr_pernr_info_gddh.
????server->request->get_form_fields(?CHANGING?fields?=?lt_fields?).
????IF?lt_fields?IS?INITIAL.
??????server->response->set_status(?code?=?404?reason?=?'未查詢到傳入參數,請檢查'?).
????ENDIF.
????LOOP?AT?lt_fields?INTO?ls_fields.
??????TRANSLATE?ls_fields-name?TO?UPPER?CASE.
??????CASE?ls_fields-name.
????????WHEN?'ZPHONE'.
??????????lv_zphone?=?ls_fields-value.
????????WHEN?'ICNUM'.
??????????lv_icnum?=?ls_fields-value.
????????WHEN?OTHERS.
??????ENDCASE.
????ENDLOOP.
????IF?lv_zphone?IS?INITIAL.
??????server->response->set_status(?code?=?404?reason?=?'手機號碼必傳,請檢查'?).
????ENDIF.
????CALL?FUNCTION?'ZHRFM_USER_INFO_GDDH'
??????EXPORTING
????????iv_zphone?=?lv_zphone
????????iv_icnum??=?lv_icnum
??????IMPORTING
????????es_info???=?ls_info.
????server->response->set_cdata(
????????/ui2/cl_json=>serialize(?data????????=?ls_info
?????????????????????????????????compress????=?abap_true
?????????????????????????????????pretty_name?=?/ui2/cl_json=>pretty_mode-camel_case?)?).
????server->response->set_status(?code?=?200?reason?=?'OK'?).
????lv_content_type?=?'application/json'.
????server->response->set_content_type(?lv_content_type?).
??ENDMETHOD.
POST請求方式:
? METHOD?post.
????TYPES:
??????BEGIN?OF?ty_input,
????????token?TYPE?string,
??????END?OF?ty_input.
????DATA:?BEGIN?OF?ls_result,
????????????data????TYPE?STANDARD?TABLE?OF?ty_input,
????????????msg?????TYPE?string,
????????????success?TYPE?string,
??????????END?OF?ls_result.
????DATA:?lt_fields???????TYPE?tihttpnvp,
??????????ls_fields???????TYPE?ihttpnvp,
??????????lv_header_query?TYPE?string,
??????????lv_data?????????TYPE?string,
??????????lv_html?????????TYPE?string,
??????????lv_body?????????TYPE?string,
??????????lv_token????????TYPE?string,
??????????lv_content_type?TYPE?string,
??????????lv_md5??????????TYPE?string,
??????????lv_algo?????????TYPE?string,
??????????ls_info?????????TYPE?zshr_pernr_info_gddh,
??????????lv_zphone???????TYPE?zphone,
??????????lv_icnum????????TYPE?psg_idnum.
????FIELD-SYMBOLS:?<fs_field>?LIKE?LINE?OF?lt_fields.
????"Json結構
????DATA:?BEGIN?OF?ls_request,
????????????datalist?TYPE?TABLE?OF?zshr_pernr_info_gddh,
??????????END?OF?ls_request.
????"傳輸結構
????DATA:?ls_itab?TYPE?zshr_pernr_info_gddh,
??????????lt_itab?TYPE?TABLE?OF?zshr_pernr_info_gddh.
????"?get?HEADER?fields
????server->request->get_header_fields(?CHANGING?fields?=?lt_fields??).
????lv_data?=?server->request->if_http_entity~get_cdata(?).
????"獲取HTTP?Body
????lv_body?=?server->request->get_cdata(?).
????"對方采用了basis認證登錄方式
*lv_token?=?'7815696ecbf1c96f'.
**TOKEN加密認證
*????TRY.
*????????lv_algo?=?'MD5'.?????????"?MD5,?SHA1,?SHA256,?SHA384,?SHA512
*????????cl_abap_message_digest=>calculate_hash_for_char(?EXPORTING?if_algorithm?=?lv_algo
*???????????????????????????????????????????????????????????????????if_data??????=?lv_token
*?????????????????????????????????????????????????????????IMPORTING
*???????????????????????????????????????????????????????????????????ef_hashstring?=?lv_md5?).
*??????CATCH?cx_root?INTO?DATA(e_text).
*????ENDTRY.
*
*
*????"將Json轉換成內表
*????TRY.
*
*????????CALL?METHOD?/ui2/cl_json=>deserialize(
*??????????EXPORTING
*????????????json????????=?lv_body
*????????????pretty_name?=?/ui2/cl_json=>pretty_mode-camel_case
*??????????CHANGING
*????????????data????????=?ls_result?).
*
*????????IF?ls_result-data?IS?NOT?INITIAL.
*??????????READ?TABLE?ls_result-data?INTO?DATA(ls_data)?INDEX?1.
*??????????IF?sy-subrc?EQ?0.
*????????????IF?ls_data-token?NE?lv_md5.
*??????????????server->response->set_status(?code?=?400?reason?=?'Token?Authority?Check?failed'?).
*??????????????server->response->set_cdata(
*??????????????????????/ui2/cl_json=>serialize(?data????????=?ls_info
*???????????????????????????????????????????????compress????=?abap_true
*???????????????????????????????????????????????pretty_name?=?/ui2/cl_json=>pretty_mode-camel_case?)?).
*??????????????EXIT.
*????????????ENDIF.
*??????????ENDIF.
*????????ENDIF.
*
*??????CATCH?cx_sy_move_cast_error.
*??????CATCH?cx_root.
*????ENDTRY..
????"?Read?the?fields?table?and?look?for?name?"~query_string"?--?this?will?contain?the?URL?query
????READ?TABLE?lt_fields?ASSIGNING?<fs_field>?WITH?KEY?name?=?'~query_string'.
????IF?sy-subrc?EQ?0.
??????SPLIT?<fs_field>-value?AT?'&'?INTO?TABLE?DATA(lt_data).
??????DELETE?lt_data?INDEX?1.
??????LOOP?AT?lt_data?INTO?DATA(lw_data).
????????CASE?sy-tabix.
??????????WHEN?1.
????????????SPLIT?lw_data?AT?'='?INTO?DATA(lv_str1)?lv_zphone.
??????????WHEN?2.
????????????SPLIT?lw_data?AT?'='?INTO?DATA(lv_str2)?lv_icnum.
????????ENDCASE.
??????ENDLOOP.
????ENDIF.
????IF?lv_zphone?IS?INITIAL.
??????CONCATENATE?'{"message":?"Please?input?ZPHONE'
????????????????????????'as?query?parameter."}'
???????????????????INTO?lv_html?SEPARATED?BY?space.
*"?Output?to?HTML
??????server->response->set_cdata(
????????EXPORTING
??????????data???=?lv_html????"?Character?data
??????).
??????server->response->set_status(?code?=?400?reason?=?'Please?input?ZPHONE'?).
????ENDIF.
????CALL?FUNCTION?'ZHRFM_USER_INFO_GDDH'
??????EXPORTING
????????iv_zphone?=?lv_zphone
????????iv_icnum??=?lv_icnum
??????IMPORTING
????????es_info???=?ls_info.
????server->response->set_status(?code?=?200?reason?=?'OK'?).
????lv_content_type?=?'application/json'.
????"設置返回格式Json
????server->response->set_content_type(?'application/json'?).
????"返回Body數據
????server->response->set_cdata(
???/ui2/cl_json=>serialize(?data????????=?ls_info
????????????????????????????compress????=?abap_true
????????????????????????????pretty_name?=?/ui2/cl_json=>pretty_mode-camel_case?)?).
??ENDMETHOD.
3.事務代碼SICF定義REST服務,配置用戶密碼(需要認證可不配置),添加處理類
登錄認證方式
SU01新增后臺接口訪問用戶,用戶類型:S(服務)
?若對方采用默認的BASIC Auth權限認證登錄方式,提供接口訪問用戶密碼給用戶。
對請求添加Basic Authentication賬號密碼,否則無法獲取
對方訪問的時候會彈出用戶密碼登錄這是SAP認證方式,如何避免彈窗呢?
如果SICF服務配置了后臺訪問的用戶密碼,安全會話設置了不受限制,則不受彈窗。但是安全考慮還是需要對方采用basic auth認證訪問登錄,也可以再加token認證匹配雙層check。sicf此處用戶密碼不配置如果給外圍系統訪問的話。
SAP這邊默認是basic認證方式, 如果訪問方接口調用直接在對方那邊維護好咱們給的接口用戶就不會彈出來了?。當然你還可以用別的認證方式甚至免密登錄都可以。你可以試試postman然后維護好你的密碼就肯定不再需要認證了。
注意因為對方basis認證登錄所以sicf用戶密碼不配置,代碼中的TOKEN獲取MD5加密匹配驗證的邏輯可跟對方協商是否需要。
SICF發布服務名稱:ZRS_GDDH_DATA
處理器清單配置ZCL_QUERY_GDDH_DATA
保存激活.測試服務
SICF發布服務給對方的各個系統訪問地址,對方對各個環境訪問地址和端口等做防火墻網絡策略申請:各個環境訪問的域名或IP地址,及對應端口,還要用RFC方式還是HTTP方式訪問可能涉及到不同的端口訪問。以及生產環境主服務器(負載均衡),還是各個應用節點服務器訪問申請可以跟BASIS確認好。
最后使用SOUPUI 或者POSTMAN接口調用聯通測試
token驗證處理
token有放body的有放header的,取token再調業務接口的模式跟對方協商好就行。?
?token方式http處理,token放請求header中處理方式:
"拼接后續要使用的tken
? CONCATENATE 'Bearer' re_login-access_token INTO re_login-access_token SEPARATED BY space.
? lo_http_client->request->if_http_entity~set_content_type( content_type = 'application/json' ).
? lo_http_client->request->if_http_entity~set_header_field( name = 'Accept' value = 'application/json' ).
? lo_http_client->request->set_method( if_http_request=>co_request_method_post ).
?
?
? lo_http_client->request->if_http_entity~set_header_field( name ? = 'Authorization' value = re_login-access_token ).
token放在請求body中的處理方式如下:
簡單一點可以理解為,雙方約定用一個相同的accesskey訪問密鑰字符串(比如XXXX-2025),做MD5方式加密,對方JAVA端給這個值放入到請求頭. sap端對這個請求獲取JAVA傳入的請求頭屬性,然后也給“XXXX-2025”這個字符串加密,看跟JAVA傳入的請求頭里面的數據是否一致,一致就通過,否則就報錯
雙方約定好一個accesskey訪問密鑰字符串,用MD5加密,再從對方傳過來的請求BODY中獲取token是否匹配一致,加密后的值比對,一致就返回,否則就報錯。
*lv_token?=?'7815696ecbf1c96fuwuj2025'.
**加密
*????TRY.
*????????lv_algo?=?'MD5'.?????????"?MD5,?SHA1,?SHA256,?SHA384,?SHA512
*????????cl_abap_message_digest=>calculate_hash_for_char(?EXPORTING?if_algorithm?=?lv_algo
*???????????????????????????????????????????????????????????????????if_data??????=?lv_token
*?????????????????????????????????????????????????????????IMPORTING
*???????????????????????????????????????????????????????????????????ef_hashstring?=?lv_md5?).
*??????CATCH?cx_root?INTO?DATA(e_text).
*????ENDTRY.
*????"將Json轉換成內表
*????TRY.
*
*????????CALL?METHOD?/ui2/cl_json=>deserialize(
*??????????EXPORTING
*????????????json????????=?lv_body
*????????????pretty_name?=?/ui2/cl_json=>pretty_mode-camel_case
*??????????CHANGING
*????????????data????????=?ls_result?).
*
*????????IF?ls_result-data?IS?NOT?INITIAL.
*??????????READ?TABLE?ls_result-data?INTO?DATA(ls_data)?INDEX?1.
*??????????IF?sy-subrc?EQ?0.
*????????????IF?ls_data-token?NE?lv_md5.
*??????????????server->response->set_status(?code?=?400?reason?=?'Token?Authority?Check?failed'?).
*??????????????server->response->set_cdata(
*??????????????????????/ui2/cl_json=>serialize(?data????????=?ls_info
*???????????????????????????????????????????????compress????=?abap_true
*???????????????????????????????????????????????pretty_name?=?/ui2/cl_json=>pretty_mode-camel_case?)?).
*??????????????EXIT.
*????????????ENDIF.
*??????????ENDIF.
*????????ENDIF.
*
*??????CATCH?cx_sy_move_cast_error.
*??????CATCH?cx_root.
*????ENDTRY..
另外,關于登錄身份認證,JAVA等外圍系統有白名單的概念,就是有一些外部接口是不需要做登錄認證的,都是通過token的方式,比如簽名方式。一些外部接口就不需要走登錄認證。 比如有個接口要給非公司內部的系統調用,訪問用戶都沒有內部員工賬號,不能登錄公司統一的IDM/authing用戶單點登錄統一身份認證平臺。?