一、功能背景 

在实际项目中,通常存在统一的用户权限管理系统,SuperMap iPortal 需与其进行集成。此类集成一般分为两种情况:一是基于 SSO 的单点登录;二是类似 OAuth2 的统一开放授权。为支持快速、高效地与项目中现有的统一用户权限系统对接,iPortal 提供了统一用户授权集成功能。

二、功能概述

集成过程的核心是通过调用用户权限系统的用户信息 API 以获取用户信息。在 SSO 场景下,iPortal 基于该身份实现用户自动登录;在开放授权场景中,则使用该身份执行服务注册等相关操作。

由于不同项目的用户权限管理系统通常为定制开发,其用户信息 API 存在较大差异。iPortal 的统一用户授权集成功能提供了灵活的配置机制,支持适配各类用户信息接口,并提供命令行工具用于配置验证,协助用户高效完成集成配置。

三、配置步骤

3.1配置概述

所有配置文件均在一下目录:【iPortal产品安装包】/webapps/iportal/WEB-INF/config/security-integration ,包含以下文件

名称 描述
httpclientbuilder.groovy 配置httpclient的Groovy脚本。用于出现问题需要诊断时对httpclient进行配置,比如配置代理拦截请求、忽略https证书验证等。正常情况下不需要修改该文件。
security-integration-sso.properties SSO单点登录集成配置文件
sso-integration.groovy SSO单点登录集成需要的Groovy脚本
security-integration-accesstoken.properties 开放授权集成配置文件
accesstoken-integration.groovy     开放授权集成配置所需要的Groovy脚本

集成过程中,核心步骤为 iPortal 调用用户权限系统的用户信息 API来获取用户信息。因此,配置主要内容包括:用户信息 API 的 URL、调用参数、返回内容类型等。这些信息在相应的 properties 文件中配置,并由 iPortal 读取以调用用户信息API来获取用户信息。由于 API 调用逻辑较为复杂,仅凭 properties 文件无法完整描述,因此还需通过对应的 Groovy 脚本进行补充处理。

3.2共用部分配置 

以下配置为 “统一开放授权” 与 “SSO单点登录” 两种场景共用,需优先完成。 

3.2.1 httpclientbuilder.groovy 配置 

该文件用于定义configure函数,可选择对 HttpClientBuilder 进行自定义配置(如设置代理、超时时间、添加证书等)。

  • 若不对HttpClientBuilder进行配置

def configure(builder) {
    return builder;
}

  • 若进行配置Proxy,示例如下

import org.apache.http.HttpHost
def configure(builder) {
    return builder.setProxy(new HttpHost("127.0.0.1", 8888));
}

3.2.2 properties 文件自定义变量配置

在 “统一开放授权” 与 “SSO单点登录”  对应的 properties 文件中,可通过*.define前缀定义自定义变量,用于存储固定参数,方便后续 Groovy 脚本引用。

属性名称 可选值 描述
*.define.X.from request/http/config/{value} 定义一个变量,X为变量名。
定义变量来源:
request表示来自sso登录时跳转回时的请求参数。
http表示需要发送一个HTTP请求
config表示是一个配置项
如果为其它值,表示是一个配置项,并且设置为该值
*.define.X.config.value   来源为config时设置变量值
*.define.X.request.querykey   来源为request请求时的query参数
*.define.X.http.url   变量来源为url时的url请求地址
*.define.X.http.function     createXRequest(此为默认值) 开放授权集成配置所需要的Groovy脚本
*.define.X.http.required   调用groovy脚本函数要求的变量
*.define.X.http.responsejsonpath   从response中获取变量值的json path,当前该http响应是json时适用
*.define.X.http.responsefunction   从response中获取变量值的groovy脚本函数

3.3统一开放授权配置 

本场景无需登录 iPortal,每个需要授权的请求必须携带 Access Token 身份凭据,除了在共用部分配置好的httpclientbuilder.groovy文件,还需再配置配2 个文件,具体步骤如下: 

3.3.1 security-integration-accesstoken.properties 配置 

该文件用于存储 Access Token 对接所需的自定义变量,变量需通过*.define前缀定义:

属性名称 可选值 描述
security-integration.accesstoken.enable true/false  
security-integration.accesstoken.define.X.*   定义变量,参照变量定义
security-integration.accesstoken.userinfoapi.url    
security-integration.accesstoken.userinfoapi.required 逗号分隔的变量名 要求的变量,会在调用groovy函数时以map传入
security-integration.accesstoken.userinfoapi.response-contenttype xml/json  

3.3.2 accesstoken-integration.groovy 配置 

定义集成所需的函数,需定义两个必填函数:createUserInfoRequest、parseUserInfo,以及变量引用所需的函数(若有)。

  • createUserInfoRequest用于构建向userinfo api发送的请求
  • parseUserInfo用于处理用户信息服务返回UserProfile json map

例如

def createUserInfoRequest(String token,required) {
return [method:"POST", query:["access-token":token], headers:[Accept:"application/json"]]
}
def parseUserInfo(jsonResponse) {
def result = [sub:jsonResponse.id]
return result;
}

3.4 SSO单点登录配置

除了在共用部分配置好的httpclientbuilder.groovy文件,还需再修改1个已有配置文件及配置2 个文件,具体如下

3.4.1 修改 iportal.xml 配置 

首先需开启 iPortal 的认证委托功能,修改【iPortal产品安装包】/webapps/iportal/WEB-INF/config/iportal.xml中<authenticationDelegation>节点下的配置:

  • <enable>:用于设置身份验证委托是否启用。默认值:false。设置为true。
  • <iframeable>:用于设置是否以 iframe 弹窗的方式展示登录页。默认值:false。保持默认值。

<IportalConfig>
    <loginSetting> 
        <!-- 统一登录方式相关配置 -->  
        <authenticationDelegation> 
          <!-- 身份验证委托是否启用,比如开启了cas且不保留内置账户,或开启了keycloak,或使用了自定义的第三方登录,都设置为true -->  
          <enable>true</enable>  
          <!-- 是否使用iframe弹窗的方式展示登录页 -->  
          <iframeable>false</iframeable>  
          <!-- iframe弹窗窗口大小 -->  
         </authenticationDelegation>  
     </loginSetting>  
 </IportalConfig>

3.4.2 security-integration-sso.properties 配置

该文件用于存储 SSO 对接所需的自定义变量,变量需通过*.define前缀定义:

属性名称 可选值 描述
security-integration.sso.enable true/false  
security-integration.sso.define.X.*   定义变量,参照变量定义
security-integration.sso.login.url-pattern http://cas/login/service={callback}&ext={state}&other 登录跳转地址模板,其中{callback}和{state}是两个预定义占位符
security-integration.sso.userinfoapi.url    
security-integration.sso.userinfoapi.required 逗号分隔的变量名 要求的变量,会在调用groovy函数时以map传入
security-integration.sso.userinfoapi.response-contenttype xml/json 当前只支持json

3.4.3 sso-integration.groovy 配置 

定义集成所需的函数,需定义两个必填函数:createUserInfoRequest、parseUserInfo),以及变量引用所需的函数(若有)。

  • createUserInfoRequest用于构建向userinfo api发送的请求
  • parseUserInfo用于处理用户信息服务返回UserProfile json map

例如

def createUserInfoRequest(required) {
    return [method:"POST", query:["access-token":required.token, code:required.code], headers:[Accept:"application/json"]]
}
def parseUserInfo(jsonResponse) {
    def result = [sub:jsonResponse.id]
    return result;
}

四、配置举例

以下以某用户信息 API 为例,说明 SSO 集成配置过程。

用户信息API说明:

#接口说明

本接口用于获取当前操作人的用户信息,使用token访问本接口时,必须使用用户登录或密码模式获取的token。查看token获取方式参考:http://zhi.gtmap.cn/share/7306526a-4cd8-444b-89d9-b8d35871bcd3

#授权信息

本接口基于outh2 Token 认证,接口认证方式:

  1. URL 传递access_token, 示例: http://127.0.0.1/test?access_token=xxxxxxxx
  2. Header设置token 示例 :Authorization bearer xxxxxxx
  3. token获取参考 http://zhi.gtmap.cn/share/9f317f41-a190-4e0e-b513-9d3f58294a69

#请求说明

方式: GET

地址: http://{域名}:{端口}/scp-account/rest/v1/users/current-user

Feign:  UserManagerClient#getCurrentUser

版本:1.0.5-SNAPSHOT

#响应结果

Copy
{
    "id":"b1e5ecd0c74b4f97ba0f62efc9f22a8b",
    "username":"wqy",
    "alias":"wqy",
    "admin":1,   // 7   分级管理员
    "enabled":1,
    "locked":0,
    "onLeave":0,
    "registerStatus":1,
    "signId":"ff808081840e717e01849dff44580042",
    "createAt":null,
    "updateAt":null,
    "expired":"2048-08-31 00:00:00",
    "password":null,
    "mobile":"15261807626",
    "email":null,
    "tel":null,
    "birthday":null,
    "gender":"男",
    "title":null,
    "resume":null,
    "address":null,
    "sequenceNumber":null,
    "idCard":null,
    "idCardType":"identity",
    "idCardFrontalId":null,
    "idCardReverseId":null,
    "userType":0,
    "jobNumber":null,
    "partyMember":"N",
    "pictureId":null,
    "caNumber":null,
    "modifyPwd":1,
    "graduateSchool":null,
    "shortNumber":null,
    "fax":null,
    "workingYears":null,
    "entryDate":null,
    "enterpriseDTO":null,
    "roleRecordList":[
        {
            "id":"8aaa077167bc00480167bf4aa6c1000f",
            "name":"068",
            "alias":"XXXXXXXXX",
            "level":3,
            "enabled":1,
            "createAt":null,
            "updateAt":null,
            "parentRecords":[

            ],
            "excludeRecords":null,
            "gradingRoleIds":null,
            "gradingAuthoritys":null,
            "orgRecords":null
        },
        {
            "id":"8aaa077165aea8ed0165aeccfc7d0002",
            "name":"ptyg",
            "alias":"员工",
            "level":0,
            "enabled":1,
            "createAt":null,
            "updateAt":null,
            "parentRecords":[

            ],
            "excludeRecords":null,
            "gradingRoleIds":null,
            "gradingAuthoritys":null,
            "orgRecords":null
        },
        {
            "id":"4028882a644acbd401644acc7cfa0004",
            "name":"admin",
            "alias":"管理员",
            "level":1,
            "enabled":1,
            "createAt":null,
            "updateAt":null,
            "parentRecords":[
                {
                    "id":"8aaa077165aea8ed0165aeccfc7d0002",
                    "name":"ptyg",
                    "alias":"员工",
                    "level":0,
                    "enabled":1,
                    "createAt":"2018-09-06 20:13:14",
                    "updateAt":"2022-07-21 13:53:30",
                    "parentRecords":null,
                    "excludeRecords":null,
                    "gradingRoleIds":null,
                    "gradingAuthoritys":null,
                    "orgRecords":null
                }
            ],
            "excludeRecords":null,
            "gradingRoleIds":null,
            "gradingAuthoritys":null,
            "orgRecords":null
        },
        {
            "id":"8aaa077167bc00480167bf4ad7fa0010",
            "name":"069",
            "alias":"初审(CS_QHFJ)",
            "level":0,
            "enabled":1,
            "createAt":null,
            "updateAt":null,
            "parentRecords":[

            ],
            "excludeRecords":null,
            "gradingRoleIds":null,
            "gradingAuthoritys":null,
            "orgRecords":null
        }
    ],
    "orgRecordList":[

    ]
}

4.1 配置用户信息 API

在security-integration-sso.properties里定义用户信息API

#启用sso集成
security-integration.sso.enable=true
#配置用户信息API的url
security-integration.sso.userinfoapi.url=http://192.168.41.71/scp-account/rest/v1/users/current-user
#根据说明,访问该url需要accesstoken参数
security-integration.sso.userinfoapi.required=accesstoken
#用户信息API content-type是json
security-integration.sso.userinfoapi.response-contenttype=json

4.2 编写 Groovy 处理脚本

想要访问该用户信息API,properties里面的信息还不够,还需在 sso-integration.groovy 中补充请求构建与响应解析逻辑:添加createUserInfoRequest和parseUserInfo两个函数,前者用于构建请求,后者用于解析响应。

def createUserInfoRequest(required) {
//iPortal会把properties里required定义的参数传入,即accesstoken
//根据说明,用户信息API是一个GET请求,access_token参数在query string里
    return [method:"GET", query:[access_token:required.accesstoken]]
}
def parseUserInfo(jsonResponse) {
    def result = [openId:jsonResponse.id, name:jsonResponse.username,nickName:jsonResponse.alias,roles:['ADMIN']]
    return result;
}

createXXXRequest返回值详细API参考,parseUserInfo返回值详细API参考

{
  "createXXXRequest": {
    "input": {
      "type": "object",
      "properties": {
        "required": {
          "type": "object",
          "description": "由 properties文件中的*.userinfoapi.required或 *.define.XXX.http.required 字段生成的map,具体key由配置项确定"
        }
      },
      "required": [
        "required"
      ]
    },
    "output": {
      "type": "object",
      "properties": {
        "method": {
          "type": "string",
          "enum": [
            "GET","POST","PUT"
          ],
          "description": "创建请求的类型"
        },
        "headers": {
          "type": "object",
          "description": "创建请求追加的header"
        },
        "query": {
          "type": "object",
          "description": "创建请求追加的queryParam"
        },
        "body": {
          "type": "object",
          "description": "返回map,如果headers里配置了Content-Type为application/json ,发送请求时使用json方式传递body,否则使用application/x-www-form-urlencoded"
        }
      },
      "required": [
        "method"
      ]
    }
  },
  "parseUserInfo": {
    "input": {
      "type": "object",
      "properties": {
        "response": {
          "type": "object",
          "description": "请求 *.userinfoapi.url 地址返回的内容转化成的map"
        }
      }
    },
    "output": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "nickName": {
          "type": "string"
        },
        "email": {
          "type": "string"
        },
        "openId": {
          "type": "string"
        },
        "roles": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "required": [
        "name"
      ]
    }
  }

 

根据该用户系统要求,access token 需通过 HTTP 请求获取,所以还需继续在 properties 文件中补充配置:

#启用sso集成
security-integration.sso.enable=true
#定义accesstoken参数,它来自http请求
security-integration.sso.define.accesstoken.from=http
#http请求地址
security-integration.sso.define.accesstoken.http.url=http://192.168.41.71/scp-account/oauth/token
#需要的参数
security-integration.sso.define.accesstoken.http.required=code,clientid,clientsecret
#如何从响应的json里获取需要的值,根据说明,是获取.access_token字段
security-integration.sso.define.accesstoken.http.responsejsonpath=.access_token
#配置用户信息API的url
security-integration.sso.userinfoapi.url=http://192.168.41.71/scp-account/rest/v1/users/current-user
#根据说明,访问该url需要accesstoken参数
security-integration.sso.userinfoapi.required=accesstoken
#用户信息API content-type是json
security-integration.sso.userinfoapi.response-contenttype=json

并在 Groovy 脚本中新增构建 token 请求的函数:因为properties里定义的参数名字是accesstoken,所以函数名是createaccesstokenRequest

def createaccesstokenRequest(required) {
    return [method:"POST", body:[code:required.code,"grant_type":"authorization_code","redirect_uri":"http://172.16.15.206:8290/iportal/sso-callback","client_id":required.clientid,"client_secret":required.clientsecret],headers:["Content-Type":"application/x-www-form-urlencoded"]]
}
def createUserInfoRequest(required) {
//iPortal会把properties里required定义的参数传入,即accesstoken
//根据说明,用户信息API是一个GET请求,access_token参数在query string里
    return [method:"GET", query:[access_token:required.accesstoken]]
}
def parseUserInfo(jsonResponse) {
    def result = [openId:jsonResponse.id, name:jsonResponse.username,nickName:jsonResponse.alias,roles:['ADMIN']]
    return result;
}

4.3 配置基础参数

Token 请求中所需的 code、clientid、clientsecret 参数也需定义来源:code是从请求里获取的参数,后两者则是配置参数,于是:

#启用sso集成
security-integration.sso.enable=true
#定义配置参数clientid
security-integration.sso.define.clientid.from=config
security-integration.sso.define.clientid.config.value=iportal
#定义配置参数clientsecret
security-integration.sso.define.clientsecret.from=config
security-integration.sso.define.clientsecret.value=lFEtXGu77f89p7xmdKtj
#定义请求参数code
security-integration.sso.define.code.from=request
#code这个参数的值是来自于请求里的query code
security-integration.sso.define.code.request.querykey=code
#定义accesstoken参数,它来自http请求
security-integration.sso.define.accesstoken.from=http
#http请求地址
security-integration.sso.define.accesstoken.http.url=http://192.168.41.71/scp-account/oauth/token
#需要的参数
security-integration.sso.define.accesstoken.http.required=code,clientid,clientsecret
#如何从响应的json里获取需要的值,根据说明,是获取.access_token字段
security-integration.sso.define.accesstoken.http.responsejsonpath=.access_token
#配置用户信息API的url
security-integration.sso.userinfoapi.url=http://192.168.41.71/scp-account/rest/v1/users/current-user
#根据说明,访问该url需要accesstoken参数
security-integration.sso.userinfoapi.required=accesstoken
#用户信息API content-type是json
security-integration.sso.userinfoapi.response-contenttype=json

至此,就完成了发送用户信息API请求的所有参数的配置。

4.4 配置 SSO 登录地址

最后配置跳转至认证系统的登录页地址:

注意url-pattern中的{callback}和{state}两个占位符,这是iPortal内置支持的占位符。iPortal会替换成真实的内容。

#启用sso集成
security-integration.sso.enable=true
#这是说明里写的登录URL
security-integration.sso.login.url-pattern=http://192.168.41.71/scp-account/oauth/authorize?client_id=iportal&redirect_uri={callback}&response_type=code&state={state}
#定义配置参数clientid
security-integration.sso.define.clientid.from=config
security-integration.sso.define.clientid.config.value=iportal
#定义配置参数clientsecret
security-integration.sso.define.clientsecret.from=config
security-integration.sso.define.clientsecret.value=lFEtXGu77f89p7xmdKtj
#定义请求参数code
security-integration.sso.define.code.from=request
#code这个参数的值是来自于请求里的query code
security-integration.sso.define.code.request.querykey=code
#定义accesstoken参数,它来自http请求
security-integration.sso.define.accesstoken.from=http
#http请求地址
security-integration.sso.define.accesstoken.http.url=http://192.168.41.71/scp-account/oauth/token
#需要的参数
security-integration.sso.define.accesstoken.http.required=code,clientid,clientsecret
#如何从响应的json里获取需要的值,根据说明,是获取.access_token字段
security-integration.sso.define.accesstoken.http.responsejsonpath=.access_token
#配置用户信息API的url
security-integration.sso.userinfoapi.url=http://192.168.41.71/scp-account/rest/v1/users/current-user
#根据说明,访问该url需要accesstoken参数
security-integration.sso.userinfoapi.required=accesstoken
#用户信息API content-type是json
security-integration.sso.userinfoapi.response-contenttype=json

到此,所有配置均已完成。

4.5 配置验证

iPortal 提供命令行工具以验证配置正确性,该工具位于:config/security-integration/security-integration-cli.jar

执行以下命令进行全流程验证(假设获取到的code是UxeLSe,实际使用时替换为手动获取的授权码):

java -Dconfig.dir=f:\supermap\iportal\supermap-iportal-11.3.0-250822-6267-win64-deploy\webapps\iportal -Dtype=sso -Daction=all -Ddefine.code=UxeLSe -jar security-integration-cli.jar

输出示例如下(敏感信息已使用 XXX 替代)。命令行工具详细展示了每一步的执行信息,若出现错误,相关提示将有效辅助配置人员快速定位问题原因。

call function : createaccesstokenRequest[{"code":"UxeLSe","clientid":"iportal","clientsecret":"XXX"}]
 
function result: {"method":"POST","body":{"code":"UxeLSe","grant_type":"authorization_code","redirect_uri":"http://172.16.15.206:8290/iportal/sso-callback","client_id":"iportal","client_secret":"XXX"},"headers":{"Content-Type":"application/x-www-form-urlencoded"}}
 
 
 
POST http://192.168.41.71/scp-account/oauth/token
 
request entity: code=UxeLSe&grant_type=authorization_code&redirect_uri=http%3A%2F%2F172.16.15.206%3A8290%2Fiportal%2Fsso-callback&client_secret=XXX&client_id=iportal
 
response code: 200
 
response entity: {"access_token":"eyJhbGciOiJSUzI1NiJ9.eyJqdGkiOiIxYTVlMjQ2ZTMwNjY0MjMxYjBjZTUzODM3MzE2YzExMiIsImV4cCI6MTc1NzQyNzUxOSwic3ViIjoiMTliMmFjMzcyMmMzNDA0Yzg5NDQzMjlkZDVkNjE1MjAiLCJwYm9keSI6IjFkZjA3NzU3NmE1MmU4ZTE1ODllM2I3ZWU5NTEwYjA3NDI5ZjE5YmVkMDI2YjM3MjUxMWZmMmM0Y2RkMGFjNzZjNTVmZmQzMDM1NTRiZWIzN2U3ZDY4NTU0MjkzYjlmNDc0MGZlYjY3ZWEzMjkxMDFmMWQ5NDRiNGIxY2I4NzNjNzc1MzQ4ODVhOTI2NTVmNzdjMmJmYTMyODhmMzRkZThlYjlhYzdiZjcxYmZhYzVlZTBmNDk4Y2U2ZjRkNzAzZGQxMjFhZGU5YWJiNGExODgzOWE3N2ZkMWIxYjM4YjBlZWY5ZWY0ZDIwNmE3Y2RjMWE0ZWVmNDMwZTU0MDQ2OTE0OWVhYTYxMjdkNjI0NGNiODU4MGI3ZTA3OWZjYTEyYzc2MGI5M2M4NDdkZTcyZmRlZDBhNGNlYWM4OTBiZmYyYjlhZWQ4NTdjZDllN2E2N2QwM2Y4Yjk2MDk1Njk5ZjQiLCJ0eXBlIjoic3NvIn0.YAkLlLUcli7-LBruU49unqZ-btoKSH0GRwIMzvmt9lxOPqvo2TQ5M9Z3Antx0wJUvKbD22lG7hGEMlahB8ir7_c-eF18E5occ8N4Dg5xyBJqz1ZMk2NK5D78d3fIR3g6xVaz_f9dmnNkd1S-ETt7y1uO_NyjOREIuZwtxuCZbiLCnpbuo0PSD-y4rkg4svFKVIlQuWBgy9Zabcfo0_zfVRxpY6BMpoW1adOKAW6wz2_X5_1k1OqcvBoquYOC5meEjtTwBalEvQJ-V26yUVXBZfoXjAqzqALIN2H9U2IBxbsnPYVTK8E4nA3g5qcA20niCKIHB5gORdqavDjoo6EuWg","refresh_token":"1a5e246e30664231b0ce53837316c112","scope":"rw","token_type":"bearer","expires_in":900}
 
 
 
call function : createUserInfoRequest[{"accesstoken":"eyJhbGciOiJSUzI1NiJ9.eyJqdGkiOiIxYTVlMjQ2ZTMwNjY0MjMxYjBjZTUzODM3MzE2YzExMiIsImV4cCI6MTc1NzQyNzUxOSwic3ViIjoiMTliMmFjMzcyMmMzNDA0Yzg5NDQzMjlkZDVkNjE1MjAiLCJwYm9keSI6IjFkZjA3NzU3NmE1MmU4ZTE1ODllM2I3ZWU5NTEwYjA3NDI5ZjE5YmVkMDI2YjM3MjUxMWZmMmM0Y2RkMGFjNzZjNTVmZmQzMDM1NTRiZWIzN2U3ZDY4NTU0MjkzYjlmNDc0MGZlYjY3ZWEzMjkxMDFmMWQ5NDRiNGIxY2I4NzNjNzc1MzQ4ODVhOTI2NTVmNzdjMmJmYTMyODhmMzRkZThlYjlhYzdiZjcxYmZhYzVlZTBmNDk4Y2U2ZjRkNzAzZGQxMjFhZGU5YWJiNGExODgzOWE3N2ZkMWIxYjM4YjBlZWY5ZWY0ZDIwNmE3Y2RjMWE0ZWVmNDMwZTU0MDQ2OTE0OWVhYTYxMjdkNjI0NGNiODU4MGI3ZTA3OWZjYTEyYzc2MGI5M2M4NDdkZTcyZmRlZDBhNGNlYWM4OTBiZmYyYjlhZWQ4NTdjZDllN2E2N2QwM2Y4Yjk2MDk1Njk5ZjQiLCJ0eXBlIjoic3NvIn0.YAkLlLUcli7-LBruU49unqZ-btoKSH0GRwIMzvmt9lxOPqvo2TQ5M9Z3Antx0wJUvKbD22lG7hGEMlahB8ir7_c-eF18E5occ8N4Dg5xyBJqz1ZMk2NK5D78d3fIR3g6xVaz_f9dmnNkd1S-ETt7y1uO_NyjOREIuZwtxuCZbiLCnpbuo0PSD-y4rkg4svFKVIlQuWBgy9Zabcfo0_zfVRxpY6BMpoW1adOKAW6wz2_X5_1k1OqcvBoquYOC5meEjtTwBalEvQJ-V26yUVXBZfoXjAqzqALIN2H9U2IBxbsnPYVTK8E4nA3g5qcA20niCKIHB5gORdqavDjoo6EuWg"}]
 
function result: {"method":"GET","query":{"access_token":"eyJhbGciOiJSUzI1NiJ9.eyJqdGkiOiIxYTVlMjQ2ZTMwNjY0MjMxYjBjZTUzODM3MzE2YzExMiIsImV4cCI6MTc1NzQyNzUxOSwic3ViIjoiMTliMmFjMzcyMmMzNDA0Yzg5NDQzMjlkZDVkNjE1MjAiLCJwYm9keSI6IjFkZjA3NzU3NmE1MmU4ZTE1ODllM2I3ZWU5NTEwYjA3NDI5ZjE5YmVkMDI2YjM3MjUxMWZmMmM0Y2RkMGFjNzZjNTVmZmQzMDM1NTRiZWIzN2U3ZDY4NTU0MjkzYjlmNDc0MGZlYjY3ZWEzMjkxMDFmMWQ5NDRiNGIxY2I4NzNjNzc1MzQ4ODVhOTI2NTVmNzdjMmJmYTMyODhmMzRkZThlYjlhYzdiZjcxYmZhYzVlZTBmNDk4Y2U2ZjRkNzAzZGQxMjFhZGU5YWJiNGExODgzOWE3N2ZkMWIxYjM4YjBlZWY5ZWY0ZDIwNmE3Y2RjMWE0ZWVmNDMwZTU0MDQ2OTE0OWVhYTYxMjdkNjI0NGNiODU4MGI3ZTA3OWZjYTEyYzc2MGI5M2M4NDdkZTcyZmRlZDBhNGNlYWM4OTBiZmYyYjlhZWQ4NTdjZDllN2E2N2QwM2Y4Yjk2MDk1Njk5ZjQiLCJ0eXBlIjoic3NvIn0.YAkLlLUcli7-LBruU49unqZ-btoKSH0GRwIMzvmt9lxOPqvo2TQ5M9Z3Antx0wJUvKbD22lG7hGEMlahB8ir7_c-eF18E5occ8N4Dg5xyBJqz1ZMk2NK5D78d3fIR3g6xVaz_f9dmnNkd1S-ETt7y1uO_NyjOREIuZwtxuCZbiLCnpbuo0PSD-y4rkg4svFKVIlQuWBgy9Zabcfo0_zfVRxpY6BMpoW1adOKAW6wz2_X5_1k1OqcvBoquYOC5meEjtTwBalEvQJ-V26yUVXBZfoXjAqzqALIN2H9U2IBxbsnPYVTK8E4nA3g5qcA20niCKIHB5gORdqavDjoo6EuWg"}}
 
 
 
GET http://192.168.41.71/scp-account/rest/v1/users/current-user?access_token=eyJhbGciOiJSUzI1NiJ9.eyJqdGkiOiIxYTVlMjQ2ZTMwNjY0MjMxYjBjZTUzODM3MzE2YzExMiIsImV4cCI6MTc1NzQyNzUxOSwic3ViIjoiMTliMmFjMzcyMmMzNDA0Yzg5NDQzMjlkZDVkNjE1MjAiLCJwYm9keSI6IjFkZjA3NzU3NmE1MmU4ZTE1ODllM2I3ZWU5NTEwYjA3NDI5ZjE5YmVkMDI2YjM3MjUxMWZmMmM0Y2RkMGFjNzZjNTVmZmQzMDM1NTRiZWIzN2U3ZDY4NTU0MjkzYjlmNDc0MGZlYjY3ZWEzMjkxMDFmMWQ5NDRiNGIxY2I4NzNjNzc1MzQ4ODVhOTI2NTVmNzdjMmJmYTMyODhmMzRkZThlYjlhYzdiZjcxYmZhYzVlZTBmNDk4Y2U2ZjRkNzAzZGQxMjFhZGU5YWJiNGExODgzOWE3N2ZkMWIxYjM4YjBlZWY5ZWY0ZDIwNmE3Y2RjMWE0ZWVmNDMwZTU0MDQ2OTE0OWVhYTYxMjdkNjI0NGNiODU4MGI3ZTA3OWZjYTEyYzc2MGI5M2M4NDdkZTcyZmRlZDBhNGNlYWM4OTBiZmYyYjlhZWQ4NTdjZDllN2E2N2QwM2Y4Yjk2MDk1Njk5ZjQiLCJ0eXBlIjoic3NvIn0.YAkLlLUcli7-LBruU49unqZ-btoKSH0GRwIMzvmt9lxOPqvo2TQ5M9Z3Antx0wJUvKbD22lG7hGEMlahB8ir7_c-eF18E5occ8N4Dg5xyBJqz1ZMk2NK5D78d3fIR3g6xVaz_f9dmnNkd1S-ETt7y1uO_NyjOREIuZwtxuCZbiLCnpbuo0PSD-y4rkg4svFKVIlQuWBgy9Zabcfo0_zfVRxpY6BMpoW1adOKAW6wz2_X5_1k1OqcvBoquYOC5meEjtTwBalEvQJ-V26yUVXBZfoXjAqzqALIN2H9U2IBxbsnPYVTK8E4nA3g5qcA20niCKIHB5gORdqavDjoo6EuWg
 
response code: 200
 
response entity: {"id":"4028882a644a8bc601644a8c6d930001","username":"admin","alias":"管理员","admin":1,"enabled":1,"locked":0,"onLeave":0,"registerStatus":1,"signId":"ff8080817f3f0388017f9c487eb8008a","createAt":null,"updateAt":null,"expired":"2090-01-01 00:00:00","password":null,"mobile":"","email":"","tel":null,"birthday":null,"gender":null,"title":null,"post":null,"resume":null,"address":null,"sequenceNumber":null,"idCard":"","idCardType":"identity","idCardFrontalId":null,"idCardReverseId":null,"userType":0,"jobNumber":null,"partyMember":"N","pictureId":null,"caNumber":null,"modifyPwd":1,"graduateSchool":null,"shortNumber":null,"fax":null,"workingYears":null,"entryDate":null,"enterpriseDTO":null,"roleRecordList":[{"id":"default~8ecU-5J_Rzit1ohU-ve14w","name":"normal","alias":"普通用户","type":null,"level":0,"enabled":1,"createAt":null,"updateAt":null,"parentRecords":[],"excludeRecords":null,"gradingRoleIds":null,"gradingAuthoritys":null,"orgRecords":null,"participateInProcess":1,"bindUserOrganization":0,"extensionConfigList":null},{"id":"default~Ru8UZuKxQkyZQT22PcAl6A","name":"deptManageRole","alias":"部门管理员","type":null,"level":0,"enabled":1,"createAt":null,"updateAt":null,"parentRecords":[],"excludeRecords":null,"gradingRoleIds":null,"gradingAuthoritys":null,"orgRecords":null,"participateInProcess":1,"bindUserOrganization":0,"extensionConfigList":null},{"id":"default~8Y6fIjtFQQGvXS9vkxUY2Q","name":"BusinessHandle","alias":"业务审核员","type":"ApproveRole","level":3,"enabled":1,"createAt":null,"updateAt":null,"parentRecords":[],"excludeRecords":null,"gradingRoleIds":null,"gradingAuthoritys":null,"orgRecords":null,"participateInProcess":1,"bindUserOrganization":0,"extensionConfigList":null},{"id":"default~xEb8b0xRTKqtM6He5VWHjg","name":"system","alias":"系统管理员","type":null,"level":4,"enabled":1,"createAt":null,"updateAt":null,"parentRecords":[],"excludeRecords":null,"gradingRoleIds":null,"gradingAuthoritys":null,"orgRecords":null,"participateInProcess":1,"bindUserOrganization":0,"extensionConfigList":null},{"id":"default~4028882a644acbd401644acc7cfa0004","name":"admin","alias":"管理员","type":null,"level":4,"enabled":1,"createAt":null,"updateAt":null,"parentRecords":[],"excludeRecords":null,"gradingRoleIds":null,"gradingAuthoritys":null,"orgRecords":null,"participateInProcess":1,"bindUserOrganization":0,"extensionConfigList":null},{"id":"default~yWHNsO-4RRyUJZ5nXQv7Ow","name":"devops","alias":"运维管理员","type":null,"level":1,"enabled":1,"createAt":null,"updateAt":null,"parentRecords":[],"excludeRecords":null,"gradingRoleIds":null,"gradingAuthoritys":null,"orgRecords":null,"participateInProcess":1,"bindUserOrganization":0,"extensionConfigList":null},{"id":"default~nggQ1FPRSxW564wQNfOogw","name":"PlatformManager","alias":"平台管理员","type":"ApproveRole","level":4,"enabled":1,"createAt":null,"updateAt":null,"parentRecords":[],"excludeRecords":null,"gradingRoleIds":null,"gradingAuthoritys":null,"orgRecords":null,"participateInProcess":1,"bindUserOrganization":0,"extensionConfigList":null},{"id":"default~FbS7975JTxSWK0Yb3IrT9Q","name":"OmEngineer","alias":"运维工程师-权限","type":"202502180002","level":0,"enabled":1,"createAt":null,"updateAt":null,"parentRecords":[],"excludeRecords":null,"gradingRoleIds":null,"gradingAuthoritys":null,"orgRecords":null,"participateInProcess":1,"bindUserOrganization":0,"extensionConfigList":null},{"id":"default~Kf0bgblfRYe3RbZcPNWnyg","name":"DataManager","alias":"数据管理员(Manager)","type":null,"level":0,"enabled":1,"createAt":null,"updateAt":null,"parentRecords":[],"excludeRecords":null,"gradingRoleIds":null,"gradingAuthoritys":null,"orgRecords":null,"participateInProcess":1,"bindUserOrganization":0,"extensionConfigList":null},{"id":"default~R1QJsapGQbiarCO_7oCe7g","name":"DataEngineer","alias":"数据工程师(Editor)","type":"202502180002","level":0,"enabled":1,"createAt":null,"updateAt":null,"parentRecords":[],"excludeRecords":null,"gradingRoleIds":null,"gradingAuthoritys":null,"orgRecords":null,"participateInProcess":1,"bindUserOrganization":0,"extensionConfigList":null},{"id":"default~Rw-oTLAGREuj36hDTLEOIA","name":"SystemManager","alias":"系统管理员-权限","type":"202502180002","level":1,"enabled":1,"createAt":null,"updateAt":null,"parentRecords":[],"excludeRecords":null,"gradingRoleIds":null,"gradingAuthoritys":null,"orgRecords":null,"participateInProcess":1,"bindUserOrganization":0,"extensionConfigList":null},{"id":"default~_q0xDfeLTdStLOrdKtEi_A","name":"BusinessCommon","alias":"业务人员-权限","type":"202502180001","level":0,"enabled":1,"createAt":null,"updateAt":null,"parentRecords":[],"excludeRecords":null,"gradingRoleIds":null,"gradingAuthoritys":null,"orgRecords":null,"participateInProcess":1,"bindUserOrganization":0,"extensionConfigList":null},{"id":"default~fOt3l19KTmCSpGRdFd1XEg","name":"BusinessManager","alias":"业务管理员-权限","type":"202502180001","level":0,"enabled":1,"createAt":null,"updateAt":null,"parentRecords":[],"excludeRecords":null,"gradingRoleIds":null,"gradingAuthoritys":null,"orgRecords":null,"participateInProcess":1,"bindUserOrganization":0,"extensionConfigList":null}],"orgRecordList":[{"id":"ca77721aa1ff4adcb918ea7ffd52dc36","code":"ADMIN_DEPART","name":"管理部门","alias":"管理部门","enabled":1,"description":null,"regionId":null,"regionCode":null,"regionName":null,"createAt":null,"updateAt":null,"weight":1,"leader":null,"parentId":"c5fb009502424f8bae31be3c0337a9d7","parentName":null,"parentCode":null,"sort":0,"isParent":false,"ancestors":null,"type":"2","orgType":"non_financial_org","crossParentId":null,"children":null,"extensionConfigList":null,"extensionConfigMap":null}],"subordinates":null,"supervisors":null,"usbKey":null,"lockedType":null,"creator":null,"relUserId":null,"link":null,"extensionConfigMap":null,"extensionConfigList":null}
 
 
 
call function : parseUserInfo[{"idCard":"","signId":"ff8080817f3f0388017f9c487eb8008a","idCardType":"identity","modifyPwd":1,"orgRecordList":[{"code":"ADMIN_DEPART","type":"2","enabled":1,"orgType":"non_financial_org","alias":"管理部门","id":"ca77721aa1ff4adcb918ea7ffd52dc36","isParent":false,"weight":1,"sort":0,"parentId":"c5fb009502424f8bae31be3c0337a9d7","name":"管理部门"}],"id":"4028882a644a8bc601644a8c6d930001","locked":0,"registerStatus":1,"userType":0,"admin":1,"enabled":1,"expired":"2090-01-01 00:00:00","alias":"管理员","email":"","mobile":"","partyMember":"N","roleRecordList":[{"level":0,"enabled":1,"bindUserOrganization":0,"participateInProcess":1,"name":"normal","alias":"普通用户","id":"default~8ecU-5J_Rzit1ohU-ve14w","parentRecords":[]},{"level":0,"enabled":1,"bindUserOrganization":0,"participateInProcess":1,"name":"deptManageRole","alias":"部门管理员","id":"default~Ru8UZuKxQkyZQT22PcAl6A","parentRecords":[]},{"level":3,"type":"ApproveRole","enabled":1,"bindUserOrganization":0,"participateInProcess":1,"name":"BusinessHandle","alias":"业务审核员","id":"default~8Y6fIjtFQQGvXS9vkxUY2Q","parentRecords":[]},{"level":4,"enabled":1,"bindUserOrganization":0,"participateInProcess":1,"name":"system","alias":"系统管理员","id":"default~xEb8b0xRTKqtM6He5VWHjg","parentRecords":[]},{"level":4,"enabled":1,"bindUserOrganization":0,"participateInProcess":1,"name":"admin","alias":"管理员","id":"default~4028882a644acbd401644acc7cfa0004","parentRecords":[]},{"level":1,"enabled":1,"bindUserOrganization":0,"participateInProcess":1,"name":"devops","alias":"运维管理员","id":"default~yWHNsO-4RRyUJZ5nXQv7Ow","parentRecords":[]},{"level":4,"type":"ApproveRole","enabled":1,"bindUserOrganization":0,"participateInProcess":1,"name":"PlatformManager","alias":"平台管理员","id":"default~nggQ1FPRSxW564wQNfOogw","parentRecords":[]},{"level":0,"type":"202502180002","enabled":1,"bindUserOrganization":0,"participateInProcess":1,"name":"OmEngineer","alias":"运维工程师-权限","id":"default~FbS7975JTxSWK0Yb3IrT9Q","parentRecords":[]},{"level":0,"enabled":1,"bindUserOrganization":0,"participateInProcess":1,"name":"DataManager","alias":"数据管理员(Manager)","id":"default~Kf0bgblfRYe3RbZcPNWnyg","parentRecords":[]},{"level":0,"type":"202502180002","enabled":1,"bindUserOrganization":0,"participateInProcess":1,"name":"DataEngineer","alias":"数据工程师(Editor)","id":"default~R1QJsapGQbiarCO_7oCe7g","parentRecords":[]},{"level":1,"type":"202502180002","enabled":1,"bindUserOrganization":0,"participateInProcess":1,"name":"SystemManager","alias":"系统管理员-权限","id":"default~Rw-oTLAGREuj36hDTLEOIA","parentRecords":[]},{"level":0,"type":"202502180001","enabled":1,"bindUserOrganization":0,"participateInProcess":1,"name":"BusinessCommon","alias":"业务人员-权限","id":"default~_q0xDfeLTdStLOrdKtEi_A","parentRecords":[]},{"level":0,"type":"202502180001","enabled":1,"bindUserOrganization":0,"participateInProcess":1,"name":"BusinessManager","alias":"业务管理员-权限","id":"default~fOt3l19KTmCSpGRdFd1XEg","parentRecords":[]}],"username":"admin","onLeave":0}]
 
function result: {"openId":"4028882a644a8bc601644a8c6d930001","name":"admin","nickName":"管理员","roles":["ADMIN"]}
 
 
 
parsed user info:
{"name":"admin","nickName":"管理员","openId":"4028882a644a8bc601644a8c6d930001","roles":["ADMIN"]}

如果出现问题想查看http请求和响应,可以修改httpclientbuilder.groovy对httpclient进行配置,添加fiddler代理,从而可以在fiddler里拦截到请求

import org.apache.http.HttpHost
def configure(builder) {
//fiddler默认端口是8888
    return builder.setProxy(new HttpHost("127.0.0.1", 8888));
}

如果API都是https的,使用fiddler拦截时还需要配置忽略证书,如下:

import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.HttpHost
def configure(builder) {
    var sslContext = new SSLContextBuilder()
                .loadTrustMaterial(null, (chain, authType) -> true)
                .build();
        SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(
                sslContext,
                NoopHostnameVerifier.INSTANCE
        );
    return builder.setSSLSocketFactory(sslSocketFactory).setProxy(new HttpHost("127.0.0.1", 8888));
}