Authentication Token

PUBLIC KEY

GET /api/clients/key

{
  "expiresAt": -1,
  "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9D3CVw6ONVPFNPTBp8vU1vHvPDf+W9De3+oILMZi2m+qG/A35U6izcpWsRjijJR2kSNOKyozN6RlsxAXPUmq1QLAGdtmR2dlPKPhVk2kKtxmVt1jyWpD4kjyjrG4DqsGITTE72QUkeLzaF34VhRXqpfTIanmUflvsVs8Cm5/XYQIDAQAB"
}

【注意】该接口所获取的公钥是经过BASE64编码之后的字符串。

Auth

POST /api/clients/auth

FORM

以FORM表单方式发送认证信息,参数如下所示:(使用上面的API获取的公钥对密码进行加密后提交)

  • HEAD Content-Type: application/x-www-form-urlencoded
  • FORM client: {client-id}
  • FORM secret: {cipher-text}

如果需要使用明文提交密码,可以额外增加一个参数ciphertext=false:

  • FORM/QUERY ciphertext: false
  • FORM secret: plain-text

JSON Payload

以JSON报文发送认证信息,参数如下所示:

  • HEAD Content-Type: application/json
  • Payload
    {
      "secret": "{cipher-text}",
      "client": "{client-id}"
    }
    

如果需要使用明文提交密码,可以额外增加一个查询参数ciphertext=false:

  • Query ciphertext: false
  • Payload
    {
      "secret": "{plain-text}",
      "client": "{client-id}"
    }
    

TEXT Cipher Payload

以文本报文发送认证信息,参数如下所示:

  • HEAD Content-Type: application/text
  • QUERY cipherPayload: true
  • Payload
    {full-json-payload-ciphertext}
    

Response Payload

Success

{
    "client": "2022",
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ2PTM7cz0xMDAxO2M9MjAyMiIsImV4cCI6MTcxMTI2NTA5NCwiaWF0IjoxNjQ4MTkzMDk0fQ.R56ukHngXoy7kAbFKA8hX8JOYSNBYHi9XlgFeOs5xYc",
    "expiresAt": 1711265094043
}

Error

{
    "status": 401,
    "code": "UNAUTHORIZED",
    "error": "UNAUTHORIZED",
    "message": "Authorization failed, cause: ..."
}

SQL Service - Query

Version

  • PATH上指定要调用服务的版本,如:
    GET /api/v1/sql-services/:sid/query
    POST /api/v1/sql-services/:sid/query
  • HEAD请求头中指定要调用服务的版本,X-SERVICE-VERSION: 1.2
    GET /api/sql-services/:sid/query
    POST /api/sql-services/:sid/query
  • 根据客户端系统订阅的版本进行响应
    GET /api/sql-services/:sid/query
    POST /api/sql-services/:sid/query

SQL Matches

    eq # Default mather
    ne

    gt
    ge
    lt
    le

    like # SQL like pattern
    contains
    starts_with
    ends_with
    not_like # SQL like pattern
    not_contains
    not_starts_with
    not_ends_with

    between
    not_between

    in
    not_in

    is_null
    not_null

POST Payload

POST /api/sql-services/:sid/query
POST /api/v1/sql-services/:sid/query

{
    "args": [{
        "name": "classId",
        "value": [1010]
    }, {
        "name": "sno",
        "value": [2020101001, 2020101002],
        "match": "not_in"
    }, {
        "name": "name",
        "value": ["周"],
        "match": "starts_with"
    }],
    "selectedColumns": ["sno", "name", "sfzID"], // Optional, 默认返回所有有权限的字段的数据
    "securityColumns": ["sfzID"], // Optional, 只针对存在脱敏的字段且拥有完整读权限的才可能需要传递(主动要求脱敏)
    "sorts": [{ // Optional
        "name": "name",
        "direction": "DESC"
    }],
    "join": "OR" // Optional, Default `AND`
}

参数解释:

  • args 入参、即查询条件,支持多种匹配方式,参考SQL Matches,单值、多值条件匹配都要把匹配值按数组格式编写 "value": [...]。是否必填取决于授权。
  • selectedColumns 可选参数,默认为空,返回所拥有权限的所有字段column数据,可以设置仅返回其中某几列的数据(有助于节约带宽、提升查询速度)。
  • securityColumns 可选参数,拥有完整读权限+支持脱敏的字段,缺省以最高权限计算,但支持客户端以低权限(脱敏读)的数据格式返回。支持["*"]代表其所拥有的权限的所有脱敏列都要脱敏。
  • sorts 可选参数,数据结果数据排序(使用服务定义的排序字段子集)
  • join 可选参数,用于 args 条件连接(缺省使用AND连接)
  • criteriaargs参数不同时使用(互斥),兼容args写法同时间支持参数条件逻辑嵌套写法。e.g.
    {
    "criteria": {
      "match": "OR",
      "children": [{
        "name": "classId",
        "value": [1010],
        "match": "eq"
      }, {
        "name": "sno",
        "value": [2020101001, 2020101002],
        "match": "not_in"
      }, {
        "match": "AND",
        "children": [] // TODO Nested
      }]
    }
    }
    // SQL伪代码 `classId = 1010 OR sno NOT IN (2020101001, 2020101002) OR (... AND ... AND ...)`
    

GET Payload

GET /api/sql-services/:sid/query
GET /api/v1/sql-services/:sid/query

rawCriteriaPayload

POST方式提交的查询参数报文使用URLEncoder进行编码,并以查询参数(rawCriteriaPayload)的方式传递。效果等同于在报文体里传递Payload

// java e.g. 
// java.net.URLEncoder.encode(payload)
// 
// js e.g.
// encodeURIComponent(payload)

base64EncodedRawCriteriaPayload

POST方式提交的查询参数报文使用Base64Encoder进行编码,并以查询参数(base64EncodedRawCriteriaPayload)的方式传递(与前者类似)。效果等同于在报文体里传递Payload

Easy arguments

优先级低于rawCriteriaPayloadbase64EncodedRawCriteriaPayload。简单查询参数需求可以使用(如简单API测试)。

  • 支持使用格式p.{argName}={value}的方式传递查询条件(eq精确匹配,如果是多值则使用in进行匹配)
  • 支持使用格式p.{argName}=~{value}的方式传递查询条件(contains模糊匹配)

其他可选参数

  • skipCountSql 分页查询数据时,true允许跳过执行COUNT SQL语句。在查询条件不变的情况下跳页查询时可以使用这一可选参数,提升查询速度。
  • totalElements 配合skipCountSql参数使用,为使得每次返回的分页信息基本正确。
  • onlyCountSql true仅执行COUNT SQL语句,数据查询API可以仅返回记录总数(Total)。
  • onlySqlDetails 辅助功能,true返回引擎动态生成的SQL信息,方便分析SQL性能和调试错误等问题。
  • illegalArgStrategy 非法参数处理策略,默认值ERROR,可选值IGNORE
  • argJoinType 使用查询参数方式逐个传递参数时有效,参数逻辑连接关系,默认值AND,可选值OR
  • selectedColumns 使用查询参数方式逐个传递参数时有效,仅返回这些数据列的内容(默认返回拥有权限的所有列的数据)。
  • securityColumns 使用查询参数方式逐个传递参数时有效,主动要求脱敏的数据列(已经配置了脱敏规则且拥有完整读权限才可能需要)。
  • sorts 设置查询结果排序,格式:COLUMN1:ASC;COLUMN2:DESC;... COLUMN1;COLUMN2:DESC;...(仅限使用查询参数方式non-payload传递criteria有效)

其他查询相关APIs

  • 1)查询数据导出API —— 导出CSV/XML/JSON等格式的数据(支持扩展com.primeton.dataservice.core.spi.converter.DataConverter接口实现其他文件格式数据导出)
  • 2)根据条件统计数据量API —— COUNT
  • 3)查询SWAGGER文档API —— SWAGGER JSON Document

(1)和(2)API与数据查询API的请求方式和参数基本一致,仅仅是PATH不同而已。

数据脱敏算法

算法实现

  • FixedLength 定长文本(数值)脱敏规则,参数列表:length=18(文本长度)、 snippets="3-5,6-9,15-17"(脱敏片段)、strict=true(严格模式:文本长度必须满足)
  • Pattern 正则脱敏规则,参数列表:pattern="正则表达式"placeholder="***"(正则匹配替换后的占位符)
  • FullName 姓名脱敏规则,参数列表:hiddenFamilyName=true(隐藏姓氏)、hiddenLastName=true(隐藏名字),能识别中文姓名 英文姓名(姓氏位置不同)、能识别中文复姓穷举(司马 欧阳 上官等)、支持隐藏姓氏或名字;
  • SimpleAddress 地址简单脱敏规则,隐藏地址中的数字,该脱敏规则无参;
  • BASE64(加密类型)安全级别较高的脱敏方式,该脱敏规则无参;
  • RSA (加密类型)安全级别最高的脱敏方式,参数列表:secretKey="TODO // RSA Public/Private Key"isPublic=true(可选参数、默认自动识别配置的秘钥是公钥还是私钥);

扩展方式

  • 实现脱敏算法接口:com.primeton.dataservice.core.spi.security.DesensitizationAlgorithm
  • 扩展的脱敏规则实现类注册为Spring Bean,并将其打包成jar文件,放入数据服务引擎${APP_HOME}/lib/目录中;
  • 脱敏算法规则名称必须唯一,DesensitizationAlgorithm#name()
  • 允许覆写数据服务引擎内置的几个脱敏算法,DesensitizationAlgorithm#name() & DesensitizationAlgorithm#getOrder()

e.g.

package com.primeton.dataservice.core.spi.security.impl;

import com.primeton.dataservice.core.spi.security.AbstractDesensitizationAlgorithm;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

/**
 * 姓名脱敏规则实现 <br>
 * - 国际化:识别中文姓名 英文姓名(姓氏位置不同)<br>
 * - 中文名:识别中文复姓穷举(司马 欧阳 上官等) <br>
 * - 规则化:隐藏姓氏 隐藏名字 <br>
 *
 * @author CHINESE (mailto:lizw@primeton.com)
 */
@Component
public class FullNameDesensitizationAlgorithm extends AbstractDesensitizationAlgorithm {

    private static final String ARG_HIDDEN_FAMILY_NAME = "hiddenFamilyName";
    private static final String ARG_HIDDEN_LAST_NAME = "hiddenLastName";

    // https://baike.baidu.com/item/%E5%A4%8D%E5%A7%93/62318?fr=aladdin
    // https://baijiahao.baidu.com/s?id=1641609835629337012&wfr=spider&for=pc
    // TODO FamilyNames as dict file
    private static final Set<String> DOUBLE_FAMILY_NAME_LIST = Collections.unmodifiableSet(Arrays.stream((
            "欧阳 太史 端木 上官 司马 东方 独孤 南宫 万俟 闻人 夏侯 诸葛 " +
            "尉迟 公羊 赫连 澹台 皇甫 宗政 濮阳 公冶 太叔 申屠 公孙 慕容 " +
            "仲孙 钟离 长孙 宇文 司徒 鲜于 司空 闾丘 子车 亓官 司寇 巫马 " +
            "公西 颛孙 壤驷 公良 漆雕 乐正 宰父 谷梁 拓跋 夹谷 轩辕 令狐 " +
            "段干 百里 呼延 东郭 南门 羊舌 微生 公户 公玉 公仪 梁丘 公仲 " +
            "公上 公门 公山 公坚 左丘 公伯 西门 公祖 第五 公乘 贯丘 公皙 " +
            "南荣 东里 东宫 仲长 子书 子桑 即墨 达奚 褚师 吴铭"
            ).split(" ")).map(String::trim).filter(StringUtils::isNotEmpty).collect(Collectors.toSet()));

    @Override
    public String name() {
        return "FullName";
    }

    @Override
    public String parse(String text, Map<String, Object> args) {
        if (StringUtils.isEmpty(text)) {
            return text;
        }
        boolean hiddenFamilyName = (Boolean) args.getOrDefault(ARG_HIDDEN_FAMILY_NAME, Boolean.FALSE);
        boolean hiddenLastName = (Boolean) args.getOrDefault(ARG_HIDDEN_LAST_NAME, Boolean.FALSE);
        if (hiddenFamilyName && hiddenLastName) {
            return placeholder(text.length());
        }
        if (!hiddenFamilyName && !hiddenLastName) {
            return text;
        }
        boolean chinese = Pattern.matches("[\\u4e00-\\u9fa5]+", text);
        if (chinese) {
            if (text.length() < 2) {
                return text; // Illegal name
            }
            if (DOUBLE_FAMILY_NAME_LIST.stream().anyMatch(text::startsWith)) {
                if (text.length() == 2) {
                    return hiddenFamilyName ? placeholder(2) : text; // Illegal name
                }
                return hiddenFamilyName ? (placeholder(2) + text.substring(2)) : (text.substring(0, 2) + placeholder(text.length() - 2));
            }
            return hiddenFamilyName ? (placeholder(1) + text.substring(1)) : (text.substring(0, 1) + placeholder(text.length() - 1));
        }
        // 英文名脱敏
        // 英语姓名的一般结构为:名+中间名+姓。如 William Jafferson Clinton
        // 分隔符:空格/句号(点)
        String separator = text.contains(" ") ? " " : ".";
        List<String> snippets = Arrays.stream(text.split(text.contains(" ") ? " " : "\\.")).map(String::trim).
                filter(StringUtils::isNotEmpty).collect(Collectors.toList());
        if (snippets.size() < 2) {
            return text; // Illegal name
        }
        return hiddenFamilyName ? (snippets.get(0) + separator + placeholder(6)) :
                (placeholder(6) + separator + snippets.stream().skip(1L).collect(Collectors.joining(separator)));
    }

    @Override
    public Map<String, Object> example() {
        Map<String, Object> args = new HashMap<>();
        args.put(ARG_HIDDEN_FAMILY_NAME, false);
        args.put(ARG_HIDDEN_LAST_NAME, true);
        return args;
    }

}

使用方式

  • SQL查询服务规格定义的每个输出参数都可以按需配置脱敏方式(服务定义默认值);
  • SQL查询服务API授权为每个客户端单独配置输出参数的脱敏方式(允许覆写默认值);
  • 数据服务平台Dashboard配置生成服务和授权时,动态按需加载脱敏规则的参数表单(如果有参数)进行渲染(UI要做成动态表单方便扩展);

安全加固 —— JSON响应报文体加密传输

对响应JSON报文中的content部分采用以下之类的算法实现进行加密处理,把加密后的报文返回给客户端、客户端使用对应的解密算法进行解密后获得原始数据。

加密实现

  • BASE64 安全级别低,简单加密方式,该脱敏规则无参;
  • RSA 高安全级别加密方式(基于RSA对称加密技术,支持使用RSA公钥或私钥进行加密),参数列表:secretKey="TODO // RSA Public/Private Key"isPublic=true(可选参数、默认自动识别配置的秘钥是公钥还是私钥);

扩展方式

  • 实现报文体加密算法接口:com.primeton.dataservice.core.spi.security.RSAPayloadEncryption
  • 扩展的加密算法实现类注册为Spring Bean,并将其打包成jar文件,放入数据服务引擎${APP_HOME}/lib/目录中;
  • 加密算法规则名称必须唯一,RSAPayloadEncryption#name()
  • 允许覆写数据服务引擎内置的几个加密算法,RSAPayloadEncryption#name() & RSAPayloadEncryption#getOrder()
  • 对于含有参数的算法实现,请到数据管理平台后端进行配置(以便支持UI自动渲染扩展的算法以及其参数的表单);
package com.primeton.dataservice.core.spi.security;

import java.util.List;
import java.util.Map;
import org.springframework.core.Ordered;

/**
 * @author CHINESE (mailto:lizw@primeton.com)
 */
public interface PayloadEncryption extends Ordered {

    @Override
    default int getOrder() {
        return 200;
    }

    String name();

    String encrypt(List<Map<String, Object>> content, Map<String, Object> args);

}

使用方式

SQL查询服务客户端授权(或变更)时设置响应报文加密传输方式(从平台提供或用户扩展的加密算法中选择一个,并填写相关参数)。

MONGODB Service - Query

Version

  • PATH上指定要调用服务的版本,如:
    GET /api/v1/mongodb-services/:sid/query
    POST /api/v1/mongodb-services/:sid/query
  • HEAD请求头中指定要调用服务的版本,X-SERVICE-VERSION: 1.2
    GET /api/mongodb-services/:sid/query
    POST /api/mongodb-services/:sid/query
  • 根据客户端系统订阅的版本进行响应
    GET /api/mongodb-services/:sid/query
    POST /api/mongodb-services/:sid/query

Match and JOIN

{
  "name": "鸠摩智"
}
{
  "name": {
    "$eq": "鸠摩智"
  }
}
{
  "name": {
    "$in": ["鸠摩智", "王语嫣", "慕容复", "段誉"]
  }
}

POST Payload

POST /api/mongodb-services/:sid/query
POST /api/v1/mongodb-services/:sid/query

{
  "sorts": [{ // 排序设置
    "name": "sno",
    "direction": "DESC"
  }],
  // "securityColumns": ["cid", "phone"], // 拥有完整读权限时可以主动要求脱敏
  // "selectedColumns": ["sfzID", "name", "mobile"], // 默认响应所有权限字段,可以选取其权限字段的子集
  "criteria": { // 查询条件,保留MONGODB原始支持的查询语法,可以使用逻辑嵌套和各种字段匹配方式 https://www.mongodb.com/docs/manual/reference/operator/query/
    "name": {
      "$in": ["鸠摩智", "王语嫣", "慕容复", "段誉"]
    }
  }
}

参数解释:

  • criteria 入参、即查询条件,支持多种匹配方式,参考MONGODB官方资料。
  • selectedColumns 可选参数,默认为空,返回所拥有权限的所有字段column数据,可以设置仅返回其中某几列的数据(有助于节约带宽、提升查询速度)。
  • securityColumns 可选参数,拥有完整读权限+支持脱敏的字段,缺省以最高权限计算,但支持客户端以低权限(脱敏读)的数据格式返回。支持["*"]代表其所拥有的权限的所有脱敏列都要脱敏。
  • sorts 可选参数,数据结果数据排序(使用服务定义的排序字段子集)

GET Payload

GET /api/mongodb-services/:sid/query
GET /api/v1/mongodb-services/:sid/query

rawCriteriaPayload

POST方式提交的查询参数报文使用URLEncoder进行编码,并以查询参数(rawCriteriaPayload)的方式传递。效果等同于在报文体里传递Payload

// java e.g. 
// java.net.URLEncoder.encode(payload)
// 
// js e.g.
// encodeURIComponent(payload)

base64EncodedRawCriteriaPayload

POST方式提交的查询参数报文使用Base64Encoder进行编码,并以查询参数(base64EncodedRawCriteriaPayload)的方式传递(与前者类似)。效果等同于在报文体里传递Payload

Easy arguments

优先级低于rawCriteriaPayloadbase64EncodedRawCriteriaPayload。简单查询参数需求可以使用(如简单API测试)。

  • 支持使用格式p.{argName}={value}的方式传递查询条件($eq精确匹配,如果是多值则使用$in进行匹配)
  • 支持使用格式p.{argName}=~{value}的方式传递查询条件($regex模糊匹配——包含)

其他可选参数

  • skipCountDocument 分页查询数据时,true允许跳过执行COUNT查询。在查询条件不变的情况下跳页查询时可以使用这一可选参数,提升查询速度。
  • totalElements 配合skipCountDocument参数使用,为使得每次返回的分页信息基本正确。
  • onlyCountDocument true仅执行COUNT查询,数据查询API可以仅返回记录总数(Total)。
  • onlyArgDetails 辅助功能,true返回引擎接收或合成的查询条件,方便分析、调试错误等问题。
  • illegalArgStrategy 非法参数处理策略,默认值ERROR,可选值IGNORE
  • argJoinType 使用查询参数方式逐个传递参数时有效(non-payload),参数逻辑连接关系,默认值AND,可选值OR NOR
  • selectedColumns 使用查询参数方式逐个传递参数时有效,仅返回这些数据列的内容(默认返回拥有权限的所有列的数据)。
  • securityColumns 使用查询参数方式逐个传递参数时有效,主动要求脱敏的数据列(已经配置了脱敏规则且拥有完整读权限才可能需要)。
  • sorts 设置查询结果排序,格式:COLUMN1:ASC;COLUMN2:DESC;... COLUMN1;COLUMN2:DESC;...(仅限使用查询参数方式non-payload传递criteria有效)

其他查询相关APIs

  • 1)查询数据导出API —— 导出CSV/XML/JSON等格式的数据(支持扩展com.primeton.dataservice.core.spi.converter.DataConverter接口实现其他文件格式数据导出)
  • 2)根据条件统计数据量API —— COUNT
  • 3)查询SWAGGER文档API —— SWAGGER JSON Document

(1)和(2)API与数据查询API的请求方式和参数基本一致,仅仅是PATH不同而已。

数据脱敏算法

与SQL查询服务共用一套,此处不做赘述

安全加固 —— JSON响应报文体加密传输

与SQL查询服务共用一套,此处不做赘述

results matching ""

    No results matching ""