配置自定义脚本

管理员可以通过自定义脚本的配置方式, 把上游身份系统中的用户字段, 经过脚本运算, 转化成腾讯统一身份的用户字段。

比如以Active Directory作为上游, 把AD中的用户同步至统一身份中, 如果AD中没有邮箱信息, 那么可以通过user.sAMAccountName + "@example.com"来转化用户的邮箱字段。

基础语法

  1. 脚本注释: 支持//或者/* */的方式, 比如

    1// this is a comment
    2user.sAMAccountName + "@example.com"
  2. 常量:

    类型说明
    booltrue或false
    int整形, 比如 1000
    float浮点, 比如 0.5
    string字符串, 需要用""或''括起来, 比如"hello"
    array数组,比如["first", "second", "third"]
    map字典,比如{first:1, second:2, third:3}
    nil空值, 类似于其他编程语言中的null
  3. 运算符:

    分类说明
    数学运算+ - * / , 比如 user.age * 2
    比较运算== != > < >= <= , 比如user.age >= 30
    逻辑运算not!,and&&,or||, 比如user.authed && user.type == "employee"
    条件运算?:三元操作符, 比如user.age >= 30 ? "tea" : "cola"
    字符运算+拼接,contains包含, startsWith开头,endsWith结尾, 比如user.name startsWith "zhang"
    字典成员访问支持[].的方式从字典中访问特定的成员, 比如user.nameuser["name"]
    数组下标成员访问支持[]的方式从数组中访问特定下标的成员, 比如user.hobbies[0]
  4. 变量声明:

    1let x = 5;
    2let y = 2;
    3x * y
  5. 内置函数

    1. 字符串操作

      函数名说明示例
      upper(str)把字符转换成大写upper("hello") 返回"HELLO"
      lower(str)把字符转换成小写lower("HELLO") 返回"hello"
      title(str)首字母大写title("hello") 返回"Hello"
      hasPrefix(str,prefix)判断是否前缀开头hasPrefix("hello", "he") 返回true
      hasSuffix(str,suffix)判断是否后缀结尾hasSuffix("hello", "lo") 返回true
      trimPrefix(str,suffix)去除字符串的指定前缀trimPrefix("helloWorld", "hello") 返回"World"
      trimSuffix(str,suffix)去除字符串的指定前缀trimSuffix("helloWorld", ",World") 返回"hello"
    2. 数字操作

      函数名说明示例
      max(n1,n2)取大值max(10,20) 返回20
      min(n1,n2)取小值min(10,20) 返回10
      abs(n)取绝对值abs(-10) 返回10
    3. 数组操作

      函数名说明示例
      all(arr,predicate)当数组中所有元素满足predicate时返回trueall([1,2,3,4], # >0) 返回true
      any(arr,predicate)当数组中任意元素满足predicate时返回trueany([1,0,2,-1], # >0) 返回true
      none(arr,predicate)当数组中所有元素都不满足predicate时返回truenone([-1,-2,-3,-4], # >0) 返回true
      filter(arr,predicate)过滤数组中所有满足predicate的元素filter([1,2,3,4], # >=3) 返回[3,4]
      len(arr)返回数组长度len([1,2,3,4]) 返回4
    4. map操作

      函数名说明示例
      keys(map)返回map中的所有keykeys({name:"zhangsan",age:20}) 返回["age","name"]
      values(map)返回map中的所有值values({name:"zhangsan",age:20}) 返回[20,"zhangsan"]
      len(map)返回map长度len({name:"zhangsan",age:20}) 返回2
    5. 类型转化

      函数名说明示例
      int(v)把整形字符串转化为integer, 若转化字符串为非整形,则报错int("123") 返回123
      float(v)把浮点型字符串转化为float, 若转化字符串为非浮点型,则报错float("1.5") 返回1.5
      string(v)把任意类型转化为stringstring(1.5) 返回"1.5"
      toJSON(v)化为json stringtoJSON({name:"zhangsan", age:20}) 返回'{ "age": 20, "name": "zhangsan" }'
      fromJSON(str)把json string反序列化fromJSON('{ "age": 20, "name": "zhangsan" }') 返回一个map对象
      toBase64(str)base64编码toBase64("hello") 返回"aGVsbG8="
      fromBase64(str)base64解码fromBase64("aGVsbG8=") 返回"hello"
    6. 其他

      函数名说明示例
      ddExtAttr(key, extension)获取钉钉用户扩展字段ddExtAttr("name","{\"name\":\"张三\",\"hobby\":\"football\"}") 返回"张三"

常见自定义脚本场景

此章节将罗列用户常见的自定义脚本场景,我们以飞书提供的数据结构为例:

1{
2 "union_id": "on_94a1ee5551019f18cd73d9f111898cf2",
3 "user_id": "3e3cf96b",
4 "open_id": "ou_7dab8a3d3cdcc9da365777c7ad535d62",
5 "name": "张三",
6 "en_name": "SanZhang",
7 "nickname": "AlexZhang",
8 "email": "zhangsan@gmail.com",
9 "mobile": "+8613011111111",
10 "mobile_visible": false,
11 "gender": 1,
12 "avatar": {
13 "avatar_72": "https://foo.icon.com/xxxx",
14 "avatar_240": "https://foo.icon.com/xxxx",
15 "avatar_640": "https://foo.icon.com/xxxx",
16 "avatar_origin": "https://foo.icon.com/xxxx"
17 },
18 "status": {
19 "is_frozen": false,
20 "is_resigned": false,
21 "is_activated": true,
22 "is_exited": false,
23 "is_unjoin": false
24 },
25 "department_ids": [
26 "od-4e6ac4d14bcd5071a37a39de902c7141"
27 ],
28 "leader_user_id": "ou_7dab8a3d3cdcc9da365777c7ad535d62",
29 "city": "杭州",
30 "country": "CN",
31 "work_station": "北楼-H34",
32 "join_time": 2147483647,
33 "is_tenant_manager": false,
34 "employee_no": "1",
35 "employee_type": 1,
36 "orders": [{
37 "department_id": "od-4e6ac4d14bcd5071a37a39de902c7141",
38 "user_order": 100,
39 "department_order": 100,
40 "is_primary_dept": true
41 }],
42 "custom_attrs": [{
43 "type": "TEXT",
44 "id": "DemoId",
45 "value": {
46 "text": "DemoText",
47 "url": "http://www.fs.cn",
48 "pc_url": "http://www.fs.cn",
49 "option_value": "option",
50 "name": "name",
51 "picture_url": "https://xxxxxxxxxxxxxxxxxx",
52 "generic_user": {
53 "id": "9b2fabg5",
54 "type": 1
55 }
56 }
57 }],
58 "enterprise_email": "demo@mail.com",
59 "job_title": "xxxxx",
60 "geo": "cn",
61 "job_level_id": "mga5oa8ayjlp9rb",
62 "job_family_id": "mga5oa8ayjlp9rb",
63 "assign_info": [{
64 "subscription_id": "7079609167680782300",
65 "license_plan_key": "suite_enterprise_e5",
66 "product_name": "旗舰版E5",
67 "i18n_name": {
68 "zh_cn": "zh_cn_name",
69 "ja_jp": "ja_jp_name",
70 "en_us": "en_name"
71 },
72 "start_time": "1674981000",
73 "end_time": "1674991000"
74 }],
75 "department_path": [{
76 "department_id": "od-4e6ac4d14bcd5071a37a39de902c7141",
77 "department_name": {
78 "name": "测试部门名1",
79 "i18n_name": {
80 "zh_cn": "测试部门名1",
81 "ja_jp": "試験部署名1",
82 "en_us": "Testingdepartmentname1"
83 }
84 },
85 "department_path": {
86 "department_ids": [
87 "od-4e6ac4d14bcd5071a37a39de902c7141"
88 ],
89 "department_path_name": {
90 "name": "测试部门名1",
91 "i18n_name": {
92 "zh_cn": "测试部门名1",
93 "ja_jp": "試験部署名1",
94 "en_us": "Testingdepartmentname1"
95 }
96 }
97 }
98 }],
99 "dotted_line_leader_user_ids": [
100 "ou_7dab8a3d3cdcc9da365777c7ad535d62"
101 ]
102}

场景一:单层级数据获取

举例:假如我们需要获取以上数据中的en_name字段属性。此时我们的脚本可以编写为user.en_name

img

场景二:多层级数据获取

举例:假如我们需要获取以上数据中的avatar_72字段属性。此时我们的脚本可以编写为user.avatar.avatar_72

img

场景三:多层级数组下标数据获取

举例:假如我们需要获取以上数据中的zh_cn字段属性。此时我们的脚本可以编写为user.department_path[0].department_name.i18n_name.zh_cn

img

场景四:数据拼装

举例:假如我们需要获取以上数据中的nickname字段属性,并将nickname字段拼接企业邮箱后缀形成企业邮箱地址存储。此时我们的脚本可以编写为user.nickname + "@example.com"

img

场景五:数据截取

举例:假如我们需要获取以上数据中的enterprise_email字段属性,但我们不需要@以后的字符。此时我们的脚本可以编写为user.nickname + "@example.com"

img

场景六:数据选择

举例:假如我们需要获取以上数据中的mobile字段属性,但我们仅需要中国区手机号,即:数据前有+86的才会存储。此时我们的脚本可以编写为user.mobile startsWith "+86" ? user.mobile : ""

img img

场景七:数据大小写转换

举例:假如我们需要获取以上数据中的nickname字段属性,但是要求nickname全部转换为大写。此时我们的脚本可以编写为upper(user.nickname)

img

场景八:数据转型

举例:假如我们需要获取以上数据中的user_order字段属性,但是要求user_order必须转换成String型才能进行存储。此时我们的脚本可以编写为string(user.orders[0].user_order)

img

常见问题

  1. user.前缀: 认证源和数据源中对用户属性的引用必须user.前缀开头, 比如user.name + "@example.com"
  2. 不存在的key报错: 比如user.invalid + "_ok", 若引用的字段invalid不存在, 则脚本语法报错, 可使用val(user.invalid, "default") + "_ok"代替