一、功能背景
在实际项目中,通常存在统一的用户权限管理系统,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 认证,接口认证方式:
- URL 传递access_token, 示例: http://127.0.0.1/test?access_token=xxxxxxxx
- Header设置token 示例 :Authorization bearer xxxxxxx
- 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));
}