大数跨境
0
0

常见私有云公有云外围系统access token获取经验分享

常见私有云公有云外围系统access token获取经验分享 建广技师
2025-04-21
2
导读:对接外围系统多了,也就见识到了各种获取外围系统接口的登录方式。现在总结一下,方便大家找到相似的登录方法进行参考。

对接外围系统多了,也就见识到了各种获取外围系统接口的登录方式。现在总结一下,方便大家找到相似的登录方法进行参考。

这里只涉及一些国产外围系统,认证方式可能不同于一些标准的认证协议,请大家辩证学习。

最简单的登录方式,就是没有登录。一些部署在内网的接口,它们不设置任何安全方式,直接推送信息到地址就完事了。虽然不安全,但对于开发来说,确实省事。常见的产品,大概率是一些中间件缓存产品,比如Redis。数据先存入数据库,后面真正的功能定时读取数据进行处理。

Basic认证,一种比较古老的认证方式。我们需要使用用户名和密码才能登录到对方的系统上。SAP发布的Restful接口也是这种认证方式。对于ABAP开发来说,常用的登录方法有两种:

    

CALL METHOD lc_http_client->AUTHENTICATEEXPORTINGUSERNAME = ‘’PASSWORD = ‘’.


            

一种方式是通过类去生成登录信息。

另一种是手动生成认证信息:

CALL METHOD lc_http_client->request->set_header_field    EXPORTING      name = 'Authorization'      value = ‘’.


这里的Value值,是将用户名+英文冒号+密码的组合,进行base64的编码后的结果。你可以在代码内用函数SSFC_BASE64_ENCODE去转换,也可以在网页找一些开源的工具加密后,直接将结果保存起来使用。    

负载中认证,原理是将获取access token的参数封装成一个json之类的东西,负载在HTTP请求的BODY中,然后推送接口,等待服务器返回access token或失败信息。例如CRM公有云平台,纷享开放平台。获取到access token后,后续的业务接口调用,也是将access token融合在接口的负载信息中,比如json中增加一个独立的结构,用来传值企业id,业务id,用户id,access token等,具体的业务数据在另外的一层数据结构中。

通过请求参数认证,首先我们要先清楚什么是请求参数。比如一个SAP发布的服务:

https://XXX:44300/sap/bc/soap/wsdl11?sap-client=100&services=ZFI_INT_001

这里的sap-client和services就是请求参数,参数值分别是100和ZFI_INT_001。能看到,他们的使用方式是在URL后面直接加问号+请求参数和值。多个请求参数通过&符号间隔。比如用友的SRM,就是这种登录方式,当然用友使用了一套更复杂的加密方式,将参数值进行加密后才通过请求参数传递的。这里专门对其进行讲解:

用友申请access token的方法,需要以下参数:appKey、timestamp、signature。

首先我们获取java的时间戳,这里用方法cl_pco_utility=>convert_abap_timestamp_to_java来生成。

我们将appKey和时间戳组合成一个字段,然后进行SHA256的加密。密钥是appselect值。使用cl_abap_hmac=>string_to_xstring将appselect值转成xstring类型的值,appKey和时间戳的组合值也用相同的方式进行格式转换。使用cl_abap_hmac=>calculate_hmac_for_raw方法,得到加密后的值。但是还没有结束,这个值需要用cl_http_utility=>escape_url进行编码,才能得到最终的signature值。    



  DATA:if_data_s        TYPE string,       if_data          TYPE xstring,       if_key           TYPE xstring,       ef_hmacb64string TYPE string,       stamp            TYPE timestampl,       stamp_char       TYPE char22,       appkey           TYPE  ze_appkey,       appselect        TYPE  ze_appselect,       timestamp        TYPE  string,       sign             TYPE  ze_sign.  SELECT SINGLE appkey appselect FROM zt3rd_sys_key INTO (appkey,appselect)    WHERE sys = 'SRM'.  IF sy-dbcnt = 0.    MESSAGE 'SRM KEY没有维护' TYPE 'I' RAISING failed.          ENDIF.  TRY.      if_data_s = appselect.      if_key = cl_abap_hmac=>string_to_xstring( if_data_s ).    CATCH cx_abap_message_digest.      MESSAGE '加密异常' TYPE 'I' RAISING failed.  ENDTRY.  GET TIME STAMP FIELD stamp.  stamp_char = stamp.  CALL METHOD cl_pco_utility=>convert_abap_timestamp_to_java    EXPORTING      iv_date      = CONV #( stamp_char(8) )      iv_time      = CONV #( stamp_char+8(6) )      iv_msec      = CONV #( stamp_char+15(3) )    IMPORTING      ev_timestamp = timestamp.  CLEAR if_data_s.  if_data_s = |appKey{ appkey }timestamp{ timestamp }|.          CONDENSE if_data_s NO-GAPS.  TRY.      if_data = cl_abap_hmac=>string_to_xstring( if_data_s ).    CATCH cx_abap_message_digest.      MESSAGE '加密异常' TYPE 'I' RAISING failed.  ENDTRY.  TRY.      CALL METHOD cl_abap_hmac=>calculate_hmac_for_raw        EXPORTING          if_algorithm     = 'SHA256'          if_key           = if_key          if_data          = if_data        IMPORTING          ef_hmacb64string = ef_hmacb64string.    CATCH cx_abap_message_digest.      MESSAGE '加密异常' TYPE 'I' RAISING failed.  ENDTRY.  sign = cl_http_utility=>escape_url( ef_hmacb64string ).*调用接口获取token  DATA: output TYPE string,        input  TYPE string.  DATA: lc_http_client  TYPE REF TO if_http_client,        l_url           TYPE string,        l_json_data     TYPE string,        l_authorization TYPE string.  SELECT SINGLE zurl zauthorization FROM zbct_adpdc INTO (l_url,l_authorization)    WHERE adpty = 'ZYONBIP_TOKEN'.  IF sy-dbcnt = 0.    MESSAGE '工具接口没有注册' TYPE 'I' RAISING failed.  ENDIF.
  l_url = |{ l_url }?appKey={ appkey }×tamp={ timestamp }&signature={ sign }|.


接口调用成功后,会得到一个带access_token的json,或者一个失败消息的json返回。

后续的业务接口调用,就简单了,只需要在url后增加?access_token=XXX,就实现了调用。    

            

讲了各种外围系统的接口登录,我在将一种不常见的接口调用方式:Form-data。

同样是Restful的接口,我们用的更多的,是那种往body中放字符串传值接口。比如json、xml,这些本质上就是在进行字符串的传值。但是难免,我们还会遇到传递文件的需求。很显然,这个时候我们就不能用lc_http_client->request->set_cdata来传值。

Form-data特殊的地方在于,每有一行数据,我们必须要给它定义一个独有的类:

      DATA: part1 TYPE REF TO if_http_entity.      DATA: part2 TYPE REF TO if_http_entity.      DATA: part3 TYPE REF TO if_http_entity.……


根据不同的名字,我们set_header_field,独立的设置标签,然后将值append_cdata。

         part1 = lc_http_client->request->if_http_entity~add_multipart( ).

            CALL METHOD part1->set_header_field              EXPORTING                name  = 'Content-Disposition'                        value = 'form-data; name="companyCode"'.

            CALL METHOD part1->append_cdata              EXPORTING                data   = ls_fields-value                offset = 0                length = lv_len.


当你真的要将文件加入本次传输的时候,首先你需要将文件转成xstring,例如函数:SCMS_BINARY_TO_XSTRING,然后将xstring用set_data或者APPEND_DATA赋值。(可不是CDATA哦,CDATA是字符串)

这里建议参考案例https://www.cnblogs.com/JingYuHai/p/17465211.html

这个例子的局限在于form-data只有一行,如果是多行,需要参照我上方的做法,多次定义form-data行的类才可以。

************************************************************************* 程 序 名:* 程序描述:ABAP调用http接口上传文件* 事务代码:************************************************************************* 修改日志        ************************************************************************* 日期     版本 修改人       描述* -------- ---- ------------ -------------------------------------------* 20230607 1.0  Amell        创建程序*************************************************************************REPORT zhttp_test MESSAGE-ID 00.************************************************************************* Tables Definitions************************************************************************TABLES: rlgrap.************************************************************************* Data Definitions                定义数据************************************************************************        TYPES: BEGIN OF ty_file,         line(1024) TYPE x,       END OF ty_file.DATA: gt_file TYPE TABLE OF ty_file.DATA: gv_file_name TYPE sdbah-actid,      gv_file_type TYPE sdbad-funct,      gv_file      TYPE xstring.************************************************************************* Includes Module                 包含模块************************************************************************************************************************************************* Selection Screen                选择屏幕************************************************************************PARAMETERS: p_file LIKE rlgrap-filename OBLIGATORY.        ************************************************************************* Initialization                  初始化事件************************************************************************INITIALIZATION.************************************************************************* At Selection Screen             PAI事件************************************************************************AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_file.  PERFORM frm_f4_file.************************************************************************* At Selection Screen Output      PBO事件************************************************************************AT SELECTION-SCREEN OUTPUT.        ************************************************************************* Report Format                   报表格式************************************************************************TOP-OF-PAGE.END-OF-PAGE.************************************************************************* Main Process                    主要逻辑************************************************************************START-OF-SELECTION.  "读取上传文件  PERFORM frm_read_upload_file.  "调用http接口上传文件  PERFORM frm_call_http_to_upload_file.END-OF-SELECTION.*&---------------------------------------------------------------------**& Form FRM_F4_FILE*&---------------------------------------------------------------------**& text*&---------------------------------------------------------------------**& -->  p1        text*& <--  p2        text*&---------------------------------------------------------------------*FORM frm_f4_file .  CALL FUNCTION 'F4_FILENAME'    IMPORTING      file_name = p_file.ENDFORM.*&---------------------------------------------------------------------**& Form FRM_READ_UPLOAD_FILE*&---------------------------------------------------------------------**& text*&---------------------------------------------------------------------**& -->  p1        text        *& <--  p2        text*&---------------------------------------------------------------------*FORM frm_read_upload_file .  DATA: lv_file_path   TYPE string,        lv_file_length TYPE i,        lv_file_name   TYPE dbmsgora-filename.  lv_file_path = p_file.  lv_file_name = p_file.  CALL FUNCTION 'SPLIT_FILENAME'    EXPORTING      long_filename  = lv_file_name "上传文件路径    IMPORTING      pure_filename  = gv_file_name "文件名称      pure_extension = gv_file_type. "文件后缀  CALL FUNCTION 'GUI_UPLOAD'    EXPORTING      filename                = lv_file_path      filetype                = 'BIN'            IMPORTING      filelength              = lv_file_length    TABLES      data_tab                = gt_file    EXCEPTIONS      file_open_error         = 1      file_read_error         = 2      no_batch                = 3      gui_refuse_filetransfer = 4      invalid_type            = 5      no_authority            = 6      unknown_error           = 7      bad_data_format         = 8      header_not_allowed      = 9      separator_not_allowed   = 10      header_too_long         = 11      unknown_dp_error        = 12      access_denied           = 13      dp_out_of_memory        = 14      disk_full               = 15      dp_timeout              = 16      OTHERS                  = 17.          IF sy-subrc <> 0.    MESSAGE s001 WITH '上传文件失败' DISPLAY LIKE 'E'.    LEAVE LIST-PROCESSING.  ENDIF.  "转xstring  CALL FUNCTION 'SCMS_BINARY_TO_XSTRING'    EXPORTING      input_length = lv_file_length    IMPORTING      buffer       = gv_file    TABLES      binary_tab   = gt_file    EXCEPTIONS      failed       = 1      OTHERS       = 2.  IF sy-subrc <> 0.    MESSAGE s001 WITH '转xstring失败' DISPLAY LIKE 'E'.    LEAVE LIST-PROCESSING.  ENDIF.ENDFORM.*&---------------------------------------------------------------------**& Form FRM_CALL_HTTP_TO_UPLOAD_FILE*&---------------------------------------------------------------------**& text*&---------------------------------------------------------------------**& -->  p1        text*& <--  p2        text*&---------------------------------------------------------------------*FORM frm_call_http_to_upload_file .  DATA: lo_http_client TYPE REF TO if_http_client, "http客户端        lo_http_entity TYPE REF TO if_http_entity, "http实体        lt_http_header TYPE tihttpnvp,             "http头部信息        ls_http_header TYPE ihttpnvp,        lv_url         TYPE string,                "http请求        lv_len         TYPE i,                     "请求数据的长度        lv_response    TYPE string,                "http响应返回信息        lv_code        TYPE i.                     "http状态码  DATA: lv_error_code TYPE sysubrc,                lv_error_msg  TYPE string.  DATA: lv_file_name TYPE savwctxt-fieldcont,        lv_name_encode TYPE savwctxt-fieldcont.  DATA: lv_content_disposition TYPE string,        lv_content_type        TYPE string.  lv_url = 'http://192.168.194.12:8080/jeecg-boot/ncip/file/upload'.  "创建http客户端请求  CALL METHOD cl_http_client=>create_by_url    EXPORTING      url                = lv_url    IMPORTING      client             = lo_http_client    EXCEPTIONS      argument_not_found = 1      plugin_not_active  = 2      internal_error     = 3      OTHERS             = 4.  "设置http为post请求  lo_http_client->request->set_method( 'POST' ).  ls_http_header-name = 'X-Access-Token'.  ls_http_header-value = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2ODYxODM1OTcsInVzZXJuYW1lIjoiYWRtaW4ifQ.fpxtvBsFDVR5WmjP3iLXhD-K7ZiULofqwQ1S_DE9Hxk'.  APPEND ls_http_header TO lt_http_header.  ls_http_header-name = 'Content-Type'.  ls_http_header-value = 'multipart/form-data'.  APPEND ls_http_header TO lt_http_header.  "设置http header  CALL METHOD lo_http_client->request->set_header_fields    EXPORTING      fields = lt_http_header.*  CALL METHOD lo_http_client->request->if_http_entity~set_formfield_encoding*    EXPORTING        *      formfield_encoding = cl_http_request=>if_http_entity~co_encoding_raw.  lo_http_entity = lo_http_client->request->if_http_entity~add_multipart( ).  "utf-8编码文件名(目的是让上传后的文件名跟原来一样,不然会乱码)  lv_file_name = gv_file_name.  CALL FUNCTION 'WWW_URLENCODE'    EXPORTING      value         = lv_file_name    IMPORTING      value_encoded = lv_name_encode.  lv_content_disposition = 'form-data; name="file"; filename="' && lv_name_encode && '.' && gv_file_type && '"'.  CALL METHOD lo_http_entity->set_header_field    EXPORTING      name  = 'Content-Disposition'      "value = 'form-data; name="file"; filename="测试文件.pdf"'      value = lv_content_disposition.          "文件后缀转小写  TRANSLATE gv_file_type TO LOWER CASE.  CASE gv_file_type.    WHEN 'jpg'.      lv_content_type = 'image/jpeg'.    WHEN 'png'.      lv_content_type = 'image/png'.    WHEN 'txt'.      lv_content_type = 'text/plain'.    WHEN 'pdf'.      lv_content_type = 'application/pdf'.    WHEN 'xlsx'.      lv_content_type = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'.    WHEN 'xls'.      lv_content_type = 'application/vnd.ms-excel'.    WHEN 'docx'.      lv_content_type = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'.            WHEN 'doc'.      lv_content_type = 'application/msword'.  ENDCASE.  CALL METHOD lo_http_entity->set_content_type    EXPORTING      content_type = lv_content_type.  lv_len = xstrlen( gv_file ).  CALL METHOD lo_http_entity->set_data    EXPORTING      data   = gv_file      offset = 0      length = lv_len.  "发送请求  CALL METHOD lo_http_client->send    EXCEPTIONS      http_communication_failure = 1      http_invalid_state         = 2              http_processing_failed     = 3      http_invalid_timeout       = 4      OTHERS                     = 5.  IF sy-subrc NE 0.    CALL METHOD lo_http_client->get_last_error      IMPORTING        code    = lv_error_code        message = lv_error_msg.  ENDIF.  "请求返回结果  CALL METHOD lo_http_client->receive    EXCEPTIONS      http_communication_failure = 1      http_invalid_state         = 2      http_processing_failed     = 3.  "请求返回的状态码  CALL METHOD lo_http_client->response->get_status            IMPORTING      code = lv_code.  "获取接口返回的数据  lv_response = lo_http_client->response->get_cdata( ).  cl_demo_output=>write( lv_response ).  cl_demo_output=>display(  ).ENDFORM.

                 

【声明】内容源于网络
0
0
建广技师
开放、互助、分享。欢迎和我们一起探究讨论关于企业数字化转型的创新技术话题。 -- JGDT Technology Innovation Team
内容 63
粉丝 0
建广技师 开放、互助、分享。欢迎和我们一起探究讨论关于企业数字化转型的创新技术话题。 -- JGDT Technology Innovation Team
总阅读6
粉丝0
内容63