其他相关资料帖可参考:
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用户单点登录统一身份认证平台。