集成开放-开放接口如何鉴权加密

使用前提

  • 已经阅读过文档【oinone 7天从入门到精通】的6.2章节-集成平台
  • 已经依赖了内置模块集成平台eip
    boot启动工程pom.xml新增jar依赖

    <dependency>
    <groupId>pro.shushi.pamirs.core</groupId>
    <artifactId>pamirs-eip2-core</artifactId>
    </dependency>
    <dependency>
    <groupId>pro.shushi.pamirs.core</groupId>
    <artifactId>pamirs-eip2-view</artifactId>
    </dependency>

    配置文件application.yml新增启动依赖模块

    pamirs:
    boot:
    modules:
      - eip
    eip:
    open-api:
      enabled: true
      route:
        # 开放接口访问IP,开放外网可以配置为0.0.0.0
        host: 127.0.0.1
        # 开放接口访问端口
        port: 8094
        # 认证Token加密的AES密钥
        aes-key: NxDZUddmvdu3QQpd5jIww2skNx6U0w0uOAXj3NUCLu8=

一、新增开放接口示例代码

开放接口类定义

package pro.shushi.pamirs.demo.api.open;

import pro.shushi.pamirs.meta.annotation.Fun;
import pro.shushi.pamirs.meta.annotation.Function;

@Fun(TestOpenApiModelService.FUN_NAMESPACE)
public interface TestOpenApiModelService {

    String FUN_NAMESPACE = "demo.open.TestOpenApiModelService";
    @Function
    TestOpenApiModel queryById(Long id);

}

开放接口实现类

package pro.shushi.pamirs.demo.core.open;

import org.apache.camel.ExtendedExchange;
import org.springframework.stereotype.Component;
import pro.shushi.pamirs.core.common.SuperMap;
import pro.shushi.pamirs.demo.api.open.TestEipConfig;
import pro.shushi.pamirs.demo.api.open.TestOpenApiModel;
import pro.shushi.pamirs.demo.api.open.TestOpenApiModelService;
import pro.shushi.pamirs.demo.api.open.TestOpenApiResponse;
import pro.shushi.pamirs.eip.api.IEipContext;
import pro.shushi.pamirs.eip.api.annotation.Open;
import pro.shushi.pamirs.eip.api.constant.EipFunctionConstant;
import pro.shushi.pamirs.eip.api.enmu.EipExpEnumerate;
import pro.shushi.pamirs.eip.api.entity.openapi.OpenEipResult;
import pro.shushi.pamirs.meta.annotation.Fun;
import pro.shushi.pamirs.meta.annotation.Function;
import pro.shushi.pamirs.meta.common.exception.PamirsException;

import java.util.Optional;

@Fun(TestOpenApiModelService.FUN_NAMESPACE)
@Component
public class TestOpenApiModelServiceImpl implements TestOpenApiModelService {

    @Override
    @Function
    public TestOpenApiModel queryById(Long id) {
        return new TestOpenApiModel().queryById(id);
    }

    @Function
    @Open
    @Open.Advanced(
            authenticationProcessorFun = EipFunctionConstant.DEFAULT_AUTHENTICATION_PROCESSOR_FUN,
            authenticationProcessorNamespace = EipFunctionConstant.FUNCTION_NAMESPACE
    )
    public OpenEipResult<TestOpenApiResponse> queryById4Open(IEipContext<SuperMap> context , ExtendedExchange exchange) {
        String id = Optional.ofNullable(String.valueOf(context.getInterfaceContext().getIteration("id"))).orElse("");
        TestOpenApiModel temp  = queryById(Long.valueOf(id));
        TestOpenApiResponse response = new TestOpenApiResponse();
        if(temp != null ) {
            response.setAge(temp.getAge());
            response.setId(temp.getId());
            response.setName(temp.getName());
        }else{
            response.setAge(1);
            response.setId(1L);
            response.setName("oinone eip test");
        }
        OpenEipResult<TestOpenApiResponse> result = new OpenEipResult<TestOpenApiResponse>(response);
        return result;
    }

    @Function
    @Open(config = TestEipConfig.class,path = "error")
    @Open.Advanced(
            httpMethod = "post",
            authenticationProcessorFun = EipFunctionConstant.DEFAULT_AUTHENTICATION_PROCESSOR_FUN,
            authenticationProcessorNamespace = EipFunctionConstant.FUNCTION_NAMESPACE
    )
    public OpenEipResult<TestOpenApiResponse> queryById4OpenError(IEipContext<SuperMap> context , ExtendedExchange exchange) {
        throw PamirsException.construct(EipExpEnumerate.SYSTEM_ERROR).appendMsg("测试异常").errThrow();
    }
}

启动工程后去开放接口配置表,将接口的业务域字段conn_group_code设置为其他分类的编码DOM00007

SELECT * from eip_eip_open_interface where is_deleted = 0 order by id desc;

集成开放-开放接口如何鉴权加密

二、为调用方创建应用

通过集成接口的应用创建,可以选择加密方式和开发接口列表中哪些接口授权该应用开放使用
集成开放-开放接口如何鉴权加密

应用创建完成后,可以在表格操作栏通过查看密钥动作查看appKey、appSecret和数据传输加密密钥的公钥
集成开放-开放接口如何鉴权加密

三、验证请求

根据appKey和appSecret获取accessToken
curl --location 'http://127.0.0.1:8094/openapi/get/access-token?tenant=pamirs' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'appKey=c65a8d76a93f4427b3702c55903ddda2' \
--data-urlencode 'appSecret=W2cMGZ0X6Av0kQOoKT4TWTaBalXkGsignr1M0Yi7+JJWJHVniiTz2mb9THGA7W5F'
调用开放接口

调用方加密请求体工具类

package pro.shushi.pamirs.demo.core.open;

import com.alibaba.fastjson.JSON;
import pro.shushi.pamirs.core.common.EncryptHelper;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 加密请求工具类
 */
public class SignRequestUtil {

    /**
     * 加密请求
     * @param params 请求参数
     * @param publicKey 数据传输加密密钥-公钥
     * @param signMethod AES/RSA
     * @return
     */
    public static String AESSignRequest(Map<String, Object> params, String publicKey, String signMethod) {
        String paramStr = JSON.toJSONString(params);
        try {
            String encryptParamStr = EncryptHelper.encryptByKey(EncryptHelper.getSecretKeySpec(signMethod, publicKey), paramStr);
            return "{ result: \"" + encryptParamStr + "\" }";
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) throws IOException {
        Map<String, Object> params = new HashMap<>();
        params.put("id", "111");
        String encryptParam = AESSignRequest(params, "FUMxjil6tdrjjBCFFy34t4ScosZOfh6hPkEwYrNFBFQ=", "AES");
        System.out.println(encryptParam);
        // 得到结果 { result: "4hSjNkx9TUDjQI8OGkbiFQ=="}
    }
}
curl --location 'http://127.0.0.1:8094/openapi/pamirs/queryById4Open' \
--header 'accessToken: T1SSd8aiJCFhsTyQepLCzRqcVsDH3wTjg9srXEZTp/S0rUbRAAIwmAX8Dgjbw0MM' \
--header 'Content-Type: application/json' \
--data '{ result: "4hSjNkx9TUDjQI8OGkbiFQ=="}'

Oinone社区 作者:nation原创文章,如若转载,请注明出处:https://doc.oinone.top/kai-fa-shi-jian/14901.html

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

Like (0)
nation's avatarnation数式员工
Previous 2024年7月25日 am12:23
Next 2024年7月25日 pm2:09

相关推荐

  • GQL GET 请求生成图片文件流 — 技术实现方案

    GQL GET 请求生成图片文件流 — 技术实现方案 基于 Oinone/Pamirs GQL GET 文件流机制,参考 FileAction#downloadFormData(查询型)与 ExcelExportTaskAction#createExportTask(同步写流),实现「按业务 ID 动态生成图片并输出文件流」的通用指南。 1. 背景与目标 1.1 需求 在业务场景中,需要根据业务 ID(如订单 ID、模板 ID、单据 ID)在后端动态渲染图片(条码、标签、证书、预览图等),并将结果以文件流形式返回给前端。 1.2 约束 复用 Oinone 既有鉴权、会话、模块路由体系,不新增独立 REST 下载接口。 与 Excel 同步导出保持一致的调用方式:通过 GET 访问 /pamirs/{module}?query=…&variables=…。 前端仅两种消费方式: 页面预览:<img :src="imageUrl" /> 触发下载:window.open(imageUrl, '_blank') 2. 参考实现 2.1 查询型文件流(图片查看应对齐此模式) 图片查看属于只读查询,应使用 query + @Function(type = QUERY),与 CDN 文件下载一致: // @oinone/kunlun-vue-ui-common/…/UploadService.ts const gql = `query{resourceFileFormQuery{downloadFormData(resourceFileForm:{downloadUrl:"${url}"}){filename}}}`; window.open(UrlHelper.appendBasePath(`/pamirs/file?query=${encodeURIComponent(gql)}`), '_blank'); // pamirs-core/pamirs-file2/…/FileAction.java @Function.Advanced(displayName = "前端下载数据", type = FunctionTypeEnum.QUERY) public ResourceFileForm downloadFormData(ResourceFileForm resourceFileForm) { // 直接写 HttpServletResponse 输出流 response.setContentType("application/octet-stream"); response.setHeader("Content-Disposition", "attachment; filename=" + …); IOUtils.copy(inputStream, response.getOutputStream()); return new ResourceFileForm(); } 图片查看用 GQL.query,不用 GQL.mutation。 2.2 同步写流机制(共用) 无论 query 还是 mutation,文件流输出的底层机制相同:在 Function/Action 执行过程中直接写 HttpServletResponse。 2.2.1 HTTP 网关:RequestController GET /pamirs/{moduleName}?query={gql}&variables={json} POST /pamirs/{moduleName} body: { query, variables } GET 与 POST 走同一执行链路: // pamirs-framework/pamirs-gateways-graph-java/…/RequestController.java @RequestMapping(value = "/pamirs/{moduleName}", method = RequestMethod.GET) public DeferredResult<String> pamirsGet( @PathVariable("moduleName") String moduleName, @RequestParam("query") String gql, @RequestParam(value = "variables", required = false) String variables, …) { PamirsClientRequestParam gqlRequest = new PamirsClientRequestParam(); gqlRequest.setQuery(gql); if (!StringUtils.isBlank(variables)) { gqlRequest.setVariables(JsonUtils.parseMap(variables)); } return pamirsPost(moduleName, gqlRequest, request, response); } variables.path 在 RequestHelper.preparePamirsRequestParam 中经 SessionPrepareApi.prepare 注入会话上下文,与前端 getSessionPath() 对应。 2.2.2 Excel 导出对照:ExcelFileServiceImpl#doExportSync Excel 同步导出使用 mutation(createExportTask),因为会创建导出任务记录;图片查看无此副作用,故用 query。 同步导出的关键:劫持 FileClient.upload,将字节直接写入当前…

    2026年7月2日
    29800
  • 环境运行时Jar版本控制

    环境运行时Jar版本控制 前景 为了避免基于低代码定义产生的元数据错乱。因此产生了运行时Jar版本检查功能。 现象 如果当前运行时依赖的Ja版本低于已安装版本,启动时会有如下类似信息提示: 解决 按照提示升级依赖Jar版本 通过启动参数 -PgoBack=true 强制覆盖安装当前运行时版本 java -jar 方式 java -jar xxx.jar -PgoBack=true [其他参数] mvn spring-boot run 方式 mvn clean compile spring-boot:run -Dspring-boot.run.arguments=”-PgoBack=true [其他参数]”

    2025年3月10日
    1.9K00
  • Oinone项目引入Nacos作为注册中心

    Oinone项目引入Nacos作为注册中心 Oinone项目的默认dubbo注册中心为zk, 实际项目中有可能要求用Nacos作注册中心。 Oinone默认引入的nacos-client-1.4.1,低版本不支持认证配置;该客户端版本支持Nacos服务1.x的和2.x的版本 一、项目中增加依赖 项目主pom引入依赖。 <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-registry-nacos</artifactId> <version>2.7.22</version> </dependency> 项目的boot工程的pom引入依赖 <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-registry-nacos</artifactId> </dependency> 二、配置修改 修改dubbo服务注册到nacos bootstrap.yml文件的配置,或者application.yml文件中修改dubbo的配置 dubbo: application: name: pamirs-demo version: 1.0.0 registry: id: pamirs-demo-registry address: nacos://192.168.0.118:8848 username: nacos # 认证的用户名(根据情况自行修改),未开启认证可以不需要配置username和password password: nacos # 认证的密码(根据情况自行修改),未开启认证可以不需要配置username和password # dubbo使用nacos的注册中心往配置中心写入配置关闭配置 use-as-metadata-center: false use-as-config-center: false config-center: address: nacos://192.168.0.118:8848 username: nacos # 认证的用户名(根据情况自行修改),未开启认证可以不需要配置username和password password: nacos # 认证的密码(根据情况自行修改),未开启认证可以不需要配置username和password metadata-report: failfast: false # 关闭错误上报的功能 address: nacos://192.168.0.118:8848 username: nacos # 认证的用户名(根据情况自行修改),未开启认证可以不需要配置username和password password: nacos # 认证的密码(根据情况自行修改),未开启认证可以不需要配置username和password protocol: name: dubbo port: -1 serialization: pamirs scan: base-packages: pro.shushi cloud: subscribed-services: 其他 Oinone构建分布式项目一些注意点,包括服务远程发布范围、关闭Dubbo元数据上报日志、Nacos作为注册中的配置 Nacos做为注册中心:如何调用其他系统的SpringCloud服务?

    2024年2月28日
    2.1K00
  • 如何加密gql请求内容

    介绍 在一些对安全等级要求比较高的场景,oinone提供了扩展前端加密请求内容,后端解密请求内容的能力,该方案要求前后端的加解密方案统一。 后端 1. 继承平台的RequestController新增一个请求类,在里面处理加密逻辑 package pro.shushi.pamirs.demo.core.controller; import org.apache.commons.lang3.StringUtils; import org.springframework.web.bind.annotation.*; import pro.shushi.pamirs.framework.gateways.graph.java.RequestController; import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j; import pro.shushi.pamirs.meta.api.dto.protocol.PamirsClientRequestParam; import pro.shushi.pamirs.user.api.utils.AES256Utils; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.HashMap; import java.util.List; import java.util.Map; @RestController @Slf4j public class DemoRequestController extends RequestController { @SuppressWarnings("unused") @RequestMapping( value = "/pamirs/{moduleName:^[a-zA-Z][a-zA-Z0-9_]+[a-zA-Z0-9]$}", method = RequestMethod.POST ) public String pamirsPost(@PathVariable("moduleName") String moduleName, @RequestBody PamirsClientRequestParam gql, HttpServletRequest request, HttpServletResponse response) { decrypt(gql); return super.pamirsPost(moduleName, gql, request, response); } @SuppressWarnings("unused") @RequestMapping( value = "/pamirs/{moduleName:^[a-zA-Z][a-zA-Z0-9_]+[a-zA-Z0-9]$}/batch", method = RequestMethod.POST ) public String pamirsBatch(@PathVariable("moduleName") String moduleName, @RequestBody List<PamirsClientRequestParam> gqls, HttpServletRequest request, HttpServletResponse response) { for (PamirsClientRequestParam gql : gqls) { decrypt(gql); } return super.pamirsBatch(moduleName, gqls, request, response); } private static final String GQL_VAR = "gql"; private void decrypt(PamirsClientRequestParam gql) { Map<String, Object> variables = null != gql.getVariables() ? gql.getVariables() : new HashMap<>(); String encodeStr = (String) variables.get(GQL_VAR); if (StringUtils.isNotBlank(encodeStr)) { variables.put(GQL_VAR, null); // TODO 此处的加密方法可以换为其他算法 String gqlQuery = AES256Utils.decrypt(encodeStr); gql.setQuery(gqlQuery); } } } 2.boot工程的启动类排除掉平台默认的RequestController类 @ComponentScan( excludeFilters = { // 该注解排除平台的RequestController类 @ComponentScan.Filter( type = FilterType.REGEX, pattern = "pro.shushi.pamirs.framework.gateways.graph.java.RequestController" ) }) public class DemoApplication { } 以下为实际项目中的启动类示例 package pro.shushi.pamirs.demo.boot; import org.apache.ibatis.annotations.Mapper; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.SpringBootApplication; import…

    2024年6月20日
    1.9K00
  • Oinone登录扩展:对接SSO(适应于4.7.8之前的版本)

    适配版本 4.7.8之前的版本 概述 在企业内部,对于已有一套完整的登录系统(SSO)的情况下,通常会要求把所有的系统都对接到SSO中;本文主要讲解用Oinone开发的项目对接SSO的具体实现。 对接步骤 1、项目自定义实现UserCookieLogin,可参考示例说明: pro.shushi.pamirs.user.api.login.UserCookieLoginFree 2、对接SSO示例 对接流程说明: 1)【必须】从请求头Header或者Query中获取到token; 2)【必须】去SSO服务端验证token的有效性; 3)【可选】根据token去服务端获取用户信息;如果token可以直接反解析出用户信息,则该步骤忽略; 4)【可选】根据实际情况用户信息是否进行DB的存储; 5)【必须】验证token有效后,生成Session和Cookie(即token换cookie); 注意超时时间需要 <= SSO服务端token失效时间。 package pro.shushi.pamirs.demo.core.sso; import com.alibaba.fastjson.JSON; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import pro.shushi.pamirs.demo.core.sso.constant.HttpConstant; import pro.shushi.pamirs.demo.core.sso.constant.SSOConstant; import pro.shushi.pamirs.demo.core.sso.constant.SessionUserTypeEnum; import pro.shushi.pamirs.demo.core.sso.model.ApiCommonTransient; import pro.shushi.pamirs.demo.core.sso.utils.AuthenticateUtils; import pro.shushi.pamirs.demo.core.sso.model.PermissionInfoResp; import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j; import pro.shushi.pamirs.meta.api.dto.model.PamirsUserDTO; import pro.shushi.pamirs.meta.api.dto.protocol.PamirsRequestVariables; import pro.shushi.pamirs.meta.api.session.PamirsSession; import pro.shushi.pamirs.meta.common.exception.PamirsException; import pro.shushi.pamirs.meta.common.spring.BeanDefinitionUtils; import pro.shushi.pamirs.meta.common.util.UUIDUtil; import pro.shushi.pamirs.resource.api.enmu.UserSignUpType; import pro.shushi.pamirs.user.api.cache.UserCache; import pro.shushi.pamirs.user.api.constants.UserConstant; import pro.shushi.pamirs.user.api.enmu.UserExpEnumerate; import pro.shushi.pamirs.user.api.enmu.UserLoginTypeEnum; import pro.shushi.pamirs.user.api.login.IUserLoginChecker; import pro.shushi.pamirs.user.api.login.UserCookieLogin; import pro.shushi.pamirs.user.api.login.UserCookieLoginSimple; import pro.shushi.pamirs.user.api.model.PamirsUser; import pro.shushi.pamirs.user.api.model.tmodel.PamirsUserTransient; import pro.shushi.pamirs.user.api.service.UserService; import pro.shushi.pamirs.user.api.utils.CookieUtil; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.concurrent.TimeUnit; /** * * @author wangxian * * 完全自定义login的过程 * 需要实现登陆部分login 以及拦截部分fetchUserIdByReq * 如果fetchUserIdByReq返回值为null的时候 将会被拦截 */ @Slf4j @Order(0) @Component public class DemoUserSSOCookieLogin extends UserCookieLogin<PamirsUser> { //刷新令牌 private static String REFRESH_TOKEN = "refreshToken"; //系统id private static String CLIENT_ID = "client-id"; //访问令牌 private static String AUTHORIZATION = "Authorization"; private IUserLoginChecker checker; @Autowired private UserService userService; @Autowired private RedisTemplate<String, String> redisTemplate; @Override public String createSessionId(HttpServletRequest request, PamirsUser idModel) { return UUIDUtil.getUUIDNumberString(); } @Override public String type() { return UserLoginTypeEnum.COOKIE.value(); } @Override public PamirsUser resolveAndVerification(PamirsUserTransient user) { if (checker == null) { checker =…

    2023年11月24日
    2.1K00

Leave a Reply

Please Login to Comment