EIP开放接口使用MD5验签发起请求(v5.x)

验签工具类

PS:该验签方法仅在pamirs-core的5.0.16版本以上可正常使用

public class EipSignUtils {

    public static final String SIGN_METHOD_MD5 = "md5";

    private static final String SIGN_METHOD_HMAC = "hmac";

    private static final String SECRET_KEY_ALGORITHM = "HmacMD5";

    private static final String MESSAGE_DIGEST_MD5 = "MD5";

    public static String signTopRequest(Map<String, String> params, String secret, String signMethod) throws IOException {
        // 第一步:检查参数是否已经排序
        String[] keys = params.keySet().toArray(new String[0]);
        Arrays.sort(keys);

        // 第二步:把所有参数名和参数值串在一起
        StringBuilder query = new StringBuilder();
        if (SIGN_METHOD_MD5.equals(signMethod)) {
            query.append(secret);
        }
        for (String key : keys) {
            String value = params.get(key);
            if (StringUtils.isNoneBlank(key, value)) {
                query.append(key).append(value);
            }
        }

        // 第三步:使用MD5/HMAC加密
        byte[] bytes;
        if (SIGN_METHOD_HMAC.equals(signMethod)) {
            bytes = encryptHMAC(query.toString(), secret);
        } else {
            query.append(secret);
            bytes = encryptMD5(query.toString());
        }

        // 第四步:把二进制转化为大写的十六进制(正确签名应该为32大写字符串,此方法需要时使用)
        return byte2hex(bytes);
    }

    private static byte[] encryptHMAC(String data, String secret) throws IOException {
        byte[] bytes;
        try {
            SecretKey secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), SECRET_KEY_ALGORITHM);
            Mac mac = Mac.getInstance(secretKey.getAlgorithm());
            mac.init(secretKey);
            bytes = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
        } catch (GeneralSecurityException e) {
            throw new IOException(e.toString(), e);
        }
        return bytes;
    }

    private static byte[] encryptMD5(String data) throws IOException {
        return encryptMD5(data.getBytes(StandardCharsets.UTF_8));
    }

    private static byte[] encryptMD5(byte[] data) throws IOException {
        try {
            MessageDigest md = MessageDigest.getInstance(MESSAGE_DIGEST_MD5);
            return md.digest(data);
        } catch (NoSuchAlgorithmException e) {
            throw new IOException(e.toString(), e);
        }
    }

    private static String byte2hex(byte[] bytes) {
        StringBuilder sign = new StringBuilder();
        for (byte aByte : bytes) {
            String hex = Integer.toHexString(aByte & 0xFF);
            if (hex.length() == 1) {
                sign.append("0");
            }
            sign.append(hex.toUpperCase());
        }
        return sign.toString();
    }
}

Oinone社区 作者:张博昊原创文章,如若转载,请注明出处:https://doc.oinone.top/backend/14224.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

(0)
张博昊的头像张博昊数式管理员
上一篇 2024年6月28日 am10:41
下一篇 2024年7月1日 pm1:58

相关推荐

  • 首次登录修改密码和自定义密码规则等

    场景描述 在某些场景下,可能需要实现 用户首次登录强制修改密码的功能,或者存在修改平台默认密码等校验规则等需求;本文将讲解不改变平台代码的情况下,如何实现这些功能需求。 首次登录修改密码 方案概述 自定义User增加是否是第一次登录的属性,登录后执行一个扩展点。 判断是否是一次登录,如果是则返回对应的状态码,前端根据状态码重定向到修改密码的页面。修改完成则充值第一次登录的标识。 PS:首次登录的标识平台前端已默认实现 扩展PamirsUser(例如:DemoUser) /** * @author wangxian */ @Model.model(DemoUser.MODEL_MODEL) @Model(displayName = "用户", labelFields = {"nickname"}) @Model.Advanced(index = {"companyId"}) public class DemoUser extends PamirsUser { public static final String MODEL_MODEL = "demo.DemoUser"; @Field.Integer @Field.Advanced(columnDefinition = "bigint DEFAULT '0'") @Field(displayName = "公司ID", invisible = true) private Long companyId; /** * 默认true->1 */ @Field.Boolean @Field.Advanced(columnDefinition = "tinyint(1) DEFAULT '1'") @Field(displayName = "是否首次登录") private Boolean firstLogin; } 定义扩展点接口(实际项目按需要增加和删减接口的定义) import pro.shushi.pamirs.meta.annotation.Ext; import pro.shushi.pamirs.meta.annotation.ExtPoint; import pro.shushi.pamirs.user.api.model.tmodel.PamirsUserTransient; @Ext(PamirsUserTransient.class) public interface PamirsUserTransientExtPoint { @ExtPoint PamirsUserTransient loginAfter(PamirsUserTransient user); @ExtPoint PamirsUserTransient loginCustomAfter(PamirsUserTransient user); @ExtPoint PamirsUserTransient firstResetPasswordAfter(PamirsUserTransient user); @ExtPoint PamirsUserTransient firstResetPasswordBefore(PamirsUserTransient user); @ExtPoint PamirsUserTransient modifyCurrentUserPasswordAfter(PamirsUserTransient user); @ExtPoint PamirsUserTransient modifyCurrentUserPasswordBefore(PamirsUserTransient user); } 编写扩展点实现(例如:DemoUserLoginExtPoint) @Order(0) @Component @Ext(PamirsUserTransient.class) @Slf4j public class DemoUserLoginExtPoint implements PamirsUserTransientExtPoint { @Override @ExtPoint.Implement public PamirsUserTransient loginAfter(PamirsUserTransient user) { return checkFirstLogin(user); } private PamirsUserTransient checkFirstLogin(PamirsUserTransient user) { //首次登录需要修改密码 Long userId = PamirsSession.getUserId(); if (userId == null) { return user; } DemoUser companyUser = new DemoUser().queryById(userId); // 判断用户是否是第一次登录,如果是第一次登录,需要返回错误码,页面重新向登录 Boolean isFirst = companyUser.getFirstLogin(); if (isFirst) { //如果是第一次登录,返回一个标识给前端。 // 首次登录的标识平台已默认实现 user.setBroken(Boolean.TRUE); user.setErrorCode(UserExpEnumerate.USER_FIRST_LOGIN_ERROR.code()); return user; } return user; } @Override public PamirsUserTransient loginCustomAfter(PamirsUserTransient user) { return checkFirstLogin(user); } @Override…

    2024年5月25日
    5.5K00
  • IWrapper、QueryWrapper和LambdaQueryWrapper使用

    条件更新updateByWrapper 通常我们在更新的时候new一个对象出来在去更新,减少更新的字段 Integer update = new DemoUser().updateByWrapper(new DemoUser().setFirstLogin(Boolean.FALSE), Pops.<DemoUser>lambdaUpdate().from(DemoUser.MODEL_MODEL).eq(IdModel::getId, userId) 使用基础模型的updateById方法更新指定字段的方法: new 一下update对象出来,更新这个对象。 WorkflowUserTask userTaskUp = new WorkflowUserTask(); userTaskUp.setId(userTask.getId()); userTaskUp.setNodeContext(json); userTaskUp.updateById(); 条件删除updateByWrapper public List<T> delete(List<T> data) { List<Long> petTypeIdList = new ArrayList(); for(T item:data){ petTypeIdList.add(item.getId()); } Models.data().deleteByWrapper(Pops.<PetType>lambdaQuery().from(PetType.MODEL_MODEL).in(PetType::getId,petTypeIdList)); return data; } 构造条件查询数据 示例1: LambdaQueryWrapper拼接查询条件 private void queryPetShops() { LambdaQueryWrapper<PetShop> query = Pops.<PetShop>lambdaQuery(); query.from(PetShop.MODEL_MODEL); query.setSortable(Boolean.FALSE); query.orderBy(true, true, PetShop::getId); List<PetShop> petShops2 = new PetShop().queryList(query); System.out.printf(petShops2.size() + ""); } 示例2: IWrapper拼接查询条件 private void queryPetShops() { IWrapper<PetShop> wrapper = Pops.<PetShop>lambdaQuery() .from(PetShop.MODEL_MODEL).eq(PetShop::getId,1L); List<PetShop> petShops4 = new PetShop().queryList(wrapper); System.out.printf(petShops4.size() + ""); } 示例3: QueryWrapper拼接查询条件 private void queryPetShops() { //使用Lambda获取字段名,防止后面改字段名漏改 String nameField = LambdaUtil.fetchFieldName(PetTalent::getName); //使用Lambda获取Clumon名,防止后面改字段名漏改 String nameColumn = PStringUtils.fieldName2Column(nameField); QueryWrapper<PetShop> wrapper2 = new QueryWrapper<PetShop>().from(PetShop.MODEL_MODEL) .eq(nameColumn, "test"); List<PetShop> petShops5 = new PetShop().queryList(wrapper2); System.out.printf(petShops5.size() + ""); } IWrapper转为LambdaQueryWrapper @Function.Advanced(type= FunctionTypeEnum.QUERY) @Function.fun(FunctionConstants.queryPage) @Function(openLevel = {FunctionOpenEnum.API}) public Pagination<PetShopProxy> queryPage(Pagination<PetShopProxy> page, IWrapper<PetShopProxy> queryWrapper) { LambdaQueryWrapper<PetShopProxy> wrapper = ((QueryWrapper<PetShopProxy>) queryWrapper).lambda(); // 非存储字段从QueryData中获取 Map<String, Object> queryData = queryWrapper.getQueryData(); if (null != queryData && !queryData.isEmpty()) { String codes = (String) queryData.get("codes"); if (org.apache.commons.lang3.StringUtils.isNotBlank(codes)) { wrapper.in(PetShopProxy::getCode, codes.split(",")); } } return new PetShopProxy().queryPage(page, wrapper); }

    2024年5月25日
    2.1K00
  • Oinone离线部署设计器JAR包

    概述 Oinone平台为合作伙伴提供了多种部署方式,这篇文章将介绍如何在私有云环境部署Oinone平台JAR包。 本文以5.2.6版本为例进行介绍。 部署环境要求 包含全部中间件及设计器服务的环境要求 CPU:8 vCPU 内存(RAM):16G以上 硬盘(HDD/SSD):60G以上 仅设计器服务的环境要求 CPU:8 vCPU 内存(RAM):8G以上 硬盘(HDD/SSD):40G以上 部署准备 在部署环境创建部署目录 mkdir -p /home/admin/oinone-designer PS:为方便管理,所有Oinone部署所需文件都应该在该目录下存放。 服务器需要安装的中间件 JDK:jdk_1.8_221版本以上 下载地址 MySQL:8.0.26版本以上 下载地址 Redis:5.0.2版本以上 下载地址 安装教程 Zookeeper:3.5.8版本以上 下载地址 安装教程 Nginx:任意版本(推荐使用源码编译安装方式,并开启rewrite、https等功能模块) Linux安装教程 下载地址 使用Docker启动所有中间件 点击下载一键部署所有中间件套件包 middleware-kits.zip 部署清单 下面列举了文章中在本地环境操作结束后的全部文件: 设计器JAR包:pamirs-designer-boot-v5.2-5.2.6.jar 离线部署结构包:oinone-designer-jar-offline.zip 第三方数据库驱动包(非MySQL数据库必须) PS:如需一次性拷贝所有部署文件到部署环境,可以将文档步骤在本地环境执行后,一次性将所有文件进行传输。 在本地环境准备部署文件 下载离线部署结构包 oinone-designer-jar-offline.zip 下载部署JAR包 5.2.6版本发布日志 查看更多版本 找到独立部署所有设计器JAR标题,下面有对应的JAR包提供下载。 例如:https://oinone-jar.oss-cn-zhangjiakou.aliyuncs.com/install/oinone-designer/pamirs-designer-boot-v5.2-5.2.6.jar 后端服务部署 将部署JAR包移动到backend目录下,并重命名为oinone-designer.jar mv pamirs-designer-boot-v5.2-5.2.6.jar backend/oinone-designer.jar PS:该名称为startup.sh脚本的默认值,可根据实际情况自行修改 将Pamirs许可证移动到backend/config目录下,并重命名为license.lic mv oinone-demo_1730163770607.lic backend/config/license.lic 加载非MySQL数据库驱动(按需) 将驱动jar文件移动到backend/lib目录下即可。 以KDB8数据库驱动kingbase8-8.6.0.jar为例 mv kingbase8-8.6.0.jar backend/lib/ PS:backend/lib目录为非设计器内置包的外部加载目录(外部库),可以添加任何jar包集成到设计器中。 修改backend/startup.sh脚本 IP:修改为可被外部访问的IP地址 DB_BASE_:base库相关数据库连接配置 DB_PAMIRS_:pamirs库相关数据库连接配置 REDIS_:Redis相关配置 MQ_NAME_SERVER:RocketMQ的name-server连接地址 ZOOKEEPER_:Zookeeper相关配置 PS:若需要配置方言或其他参数,可直接修改backend/config/application.yml配置文件,变量仅用于简单配置场景 执行startup.sh脚本启动 sh startup.sh 执行完成后会打印三个路径 后端路径:backend root path: /path/to/backend 前端路径:frontend root path: /path/to/frontend Nginx配置路径:nginx services path: /path/to/nginx Nginx配置 在本地nginx服务中找到nginx.conf,并添加Nginx配置路径为加载目录 http { … include /path/to/nginx/*.conf; } 修改结构包中的default.conf第7行root配置为前端路径到dist目录下 server { … root /path/to/frontend/dist; } 修改结构包中的oss.conf第30行alias配置为前端路径到static目录下 server { … location /static { … alias /path/to/frontend/static; } } 访问服务 使用http://127.0.0.1:9090访问服务

    2024年11月1日
    1.6K00
  • 【后端】项目开发后端知识要点地图

    大类 明细 文档链接 平台基础 如何开发Action,理解前后端协议 如何开发Action,理解前后端协议 CDN配置及文件操作相关 OSS(CDN)配置和文件系统的一些操作 MINIO无公网访问地址下OSS的配置 MINIO无公网访问地址下OSS的配置 分库分表与自定义分表规则 分库分表与自定义分表规则 Oinone引入搜索引擎(增强模型) Oinone引入搜索引擎(增强模型) 引入搜索/增强模型Channel)常见问题解决办法 引入搜索(增强模型Channel)常见问题解决办法 框架之MessageHub(信息提示) 框架之MessageHub(信息提示) DsHint和BatchSizeHint的使用 DsHint(指定数据源)和BatchSizeHint(查询批次数量) Oinone连接外部数据源方案 Oinone连接外部数据源方案 如何自定义SQL(Mapper)语句 如何自定义SQL(Mapper)语句 IWrapper、QueryWrapper和LambdaQueryWrapper使用 IWrapper、QueryWrapper和LambdaQueryWrapper使用 如何在代码中使用自增ID、手动方式获取CODE 如何在代码中使用自增ID、手动方式获取CODE 函数之触发与定时配置和示例 函数之触发与定时配置和示例 函数之异步执行 函数之异步执行 查询时自定义排序字段和排序规则 查询时自定义排序字段和排序规则 非存储字段搜索 非存储字段搜索,适应灵活的搜索场景 枚举/二进制枚举/多值枚举 如何使用位运算的数据字典 全局首页及应用首页配置方法(homepage) 全局首页及应用首页配置方法(homepage) 缓存连接由Jedis切换为Lettuce 缓存连接由Jedis切换为Lettuce GraphQL请求:后端接口实现逻辑解析 GraphQL请求:后端接口实现逻辑解析 Nacos支持 Nacos作为注册中心 Oinone项目引入Nacos作为注册中心 Nacos作为配置中心 Oinone项目引入Nacos作为配置中心 Nacos做为注册中心调用SpringCloud服务 Nacos做为注册中心调用SpringCloud服务 分布式相关 如何构建分布式项目 Oinone如何支持构建分布式项目 构建分布式项目一些要点(dubbo日志关闭等) Oinone构建分布式项目一些注意点 信创支持 后端部署使用达梦数据库 【达梦】后端使用达梦数据库 后端部署使用PostgreSQL数据库 【PostgreSQL】后端使用PostgreSQL数据库 后端部署使用OpenGauss数据库 【OpenGauss】后端使用OpenGauss数据库 后端部署使用MSSQL数据库(SQLServer) 【MSSQL】后端部署使用MSSQL数据库(SQLServer) 东方通Web和Tomcat部署Oinone项目 东方通Web和Tomcat部署Oinone项目 常见扩展 如何增加用户中心的菜单 如何增加用户中心的菜单 导入导出 如何批量导入 如何批量导入 如何支持多Excel多个Sheet导入功能 如何支持多Excel多个Sheet导入功能 如何自定义Excel导入功能 如何自定义Excel导入功能 如何自定义Excel导出功能 如何自定义Excel导出功能 如何自定义表达式 如何自定义表达式 登录扩展 对接外部SSO Oinone登录扩展:对接SSO(4.7.8及之后的版本) 自定义占位符 自定义RSQL占位符及在权限中使用 自定义RSQL占位符(placeholder)及在权限中使用 自定义数据权限拦截处理 自定义数据权限拦截处理 设计器公共 后端无代码设计器Jar包启动方法 后端无代码设计器Jar包启动方法 界面设计器 页面跳转时增加跳转参数 页面跳转时增加跳转参数 界面设计器的导入导出 界面设计器的导入导出 流程设计器 项目中工作流引入和流程触发 项目中工作流引入和流程触发 流程扩展自定义函数示例代码汇总 工作流-流程扩展自定义函数示例代码汇总 工作流-流程代办等页面自定义 工作流-流程代办等页面自定义 审核撤回/回退/拒绝钩子使用 工作流审核撤回/回退/拒绝钩子使用 流程设计器的导入导出 流程设计器的导入导出 如何添加工作流运行时依赖 如何添加工作流运行时依赖 数据可视化 项目中图表设计器引入 数据可视化-项目中数据可视化的实现引入 自定义图表模版 数据可视化中图表的低无一体 图表设计器数据获取示例 数据可视化-数据可视化数据获取示例 如何添加数据可视化运行时依赖 如何添加数据可视化运行时依赖 图表设计器的设计数据导入导出 图表设计器的设计数据导入导出

    2024年5月21日
    2.4K00
  • 如何自定义Excel导出功能

    介绍 在平台提供的默认导出功能无法满足业务需求的时候,我们可以自定义导出功能,以满足业务中个性化的需求。 功能示例 继承平台的导出任务模型,加上需要在导出的弹窗视图需要展示的字段 package pro.shushi.pamirs.demo.api.model; import pro.shushi.pamirs.file.api.model.ExcelExportTask; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; @Model.model(DemoItemExportTask.MODEL_MODEL) @Model(displayName = "商品-Excel导出任务") public class DemoItemExportTask extends ExcelExportTask { public static final String MODEL_MODEL = "demo.DemoItemExportTask"; // 自定义显示的字段 @Field.String @Field(displayName = "发布人") private String publishUserName; } 编写自定义导出弹窗视图的数据初始化方法和导出提交的action package pro.shushi.pamirs.demo.core.action; import org.springframework.stereotype.Component; import pro.shushi.pamirs.demo.api.model.DemoItemExportTask; import pro.shushi.pamirs.file.api.action.ExcelExportTaskAction; import pro.shushi.pamirs.file.api.model.ExcelWorkbookDefinition; import pro.shushi.pamirs.file.api.service.ExcelFileService; import pro.shushi.pamirs.meta.annotation.Action; import pro.shushi.pamirs.meta.annotation.Function; import pro.shushi.pamirs.meta.annotation.Model; import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j; import pro.shushi.pamirs.meta.enmu.ActionContextTypeEnum; import pro.shushi.pamirs.meta.enmu.FunctionOpenEnum; import pro.shushi.pamirs.meta.enmu.FunctionTypeEnum; import pro.shushi.pamirs.meta.enmu.ViewTypeEnum; @Slf4j @Component @Model.model(DemoItemExportTask.MODEL_MODEL) public class DemoItemExcelExportTaskAction extends ExcelExportTaskAction { public DemoItemExcelExportTaskAction(ExcelFileService excelFileService) { super(excelFileService); } @Action(displayName = "导出", contextType = ActionContextTypeEnum.CONTEXT_FREE, bindingType = {ViewTypeEnum.TABLE}) public DemoItemExportTask createExportTask(DemoItemExportTask data) { if (data.getWorkbookDefinitionId() != null) { ExcelWorkbookDefinition workbookDefinition = new ExcelWorkbookDefinition(); workbookDefinition.setId(data.getWorkbookDefinitionId()); data.setWorkbookDefinition(workbookDefinition); } super.createExportTask(data); return data; } /** * @param data * @return */ @Function(openLevel = FunctionOpenEnum.API) @Function.Advanced(type = FunctionTypeEnum.QUERY) public DemoItemExportTask construct(DemoItemExportTask data) { data.construct(); return data; } } 编写导出的数据处理逻辑,此处可以拿到导出弹窗内自定义的字段提交的值,然后根据这些值处理自定义逻辑 package pro.shushi.pamirs.demo.core.excel.extPoint; import org.springframework.stereotype.Component; import pro.shushi.pamirs.demo.api.model.DemoItem; import pro.shushi.pamirs.demo.api.model.DemoItemExportTask; import pro.shushi.pamirs.demo.api.model.DemoItemImportTask; import pro.shushi.pamirs.file.api.context.ExcelDefinitionContext; import pro.shushi.pamirs.file.api.enmu.ExcelTemplateTypeEnum; import pro.shushi.pamirs.file.api.extpoint.ExcelExportFetchDataExtPoint; import pro.shushi.pamirs.file.api.extpoint.impl.ExcelExportSameQueryPageTemplate; import pro.shushi.pamirs.file.api.model.ExcelExportTask; import pro.shushi.pamirs.file.api.model.ExcelWorkbookDefinition; import pro.shushi.pamirs.file.api.util.ExcelHelper; import pro.shushi.pamirs.file.api.util.ExcelTemplateInit; import pro.shushi.pamirs.meta.annotation.ExtPoint; import java.util.Collections; import java.util.List; @Component public class DemoItemExportExtPoint extends ExcelExportSameQueryPageTemplate implements ExcelTemplateInit , ExcelExportFetchDataExtPoint…

    2024年1月3日
    1.3K00

Leave a Reply

登录后才能评论