如何加密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 org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration;
import org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.system.ApplicationPid;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.util.StopWatch;
import pro.shushi.pamirs.framework.connectors.data.kv.RedisClusterConfig;
import pro.shushi.pamirs.framework.gateways.graph.java.RequestController;
import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j;

import java.io.File;
import java.io.IOException;

@ComponentScan(
        basePackages = {
                "pro.shushi.pamirs.meta",
                "pro.shushi.pamirs.framework.connectors",
                "pro.shushi.pamirs.framework",
                "pro.shushi.pamirs",
                "pro.shushi.pamirs.demo"
        },
        excludeFilters = {
                @ComponentScan.Filter(
                        type = FilterType.ASSIGNABLE_TYPE,
                        value = {RedisAutoConfiguration.class, RedisRepositoriesAutoConfiguration.class, RedisClusterConfig.class}
                ),
                // 该注解排除平台的RequestController类
                @ComponentScan.Filter(type = FilterType.REGEX,
                        pattern = "pro.shushi.pamirs.framework.gateways.graph.java.RequestController")
        })
@Slf4j
@EnableTransactionManagement
@EnableAsync
@MapperScan(value = {"pro.shushi.pamirs", "pro.shushi.pamirs.demo"}, annotationClass = Mapper.class)
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, FreeMarkerAutoConfiguration.class})
public class DemoApplication {

    public static void main(String[] args) throws IOException {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        log.info("oinoneDemo工程 Application loading...");

        new ApplicationPid().write(new File("pamirs-demo.pid"));

        new SpringApplicationBuilder(DemoApplication.class)
                .web(WebApplicationType.SERVLET)
                .run(args);

        stopWatch.stop();

        log.info("启动耗时 {} s", stopWatch.getTotalTimeSeconds());
    }
}

前端

1.新增工具类EncryptRequestUtil.ts

import { encrypt, NetworkMiddlewareHandler } from '@kunlun/dependencies';

export const encryptMiddleWare: NetworkMiddlewareHandler = (operation, forward) => {
  // 下面一行代码为默认的加密方法,可以替换为自己的算法
  const encryptedGqlString = encrypt(operation!.query!.loc!.source.body);
  operation!.query = null as any; // 清空原始 query
  operation.variables = { ...operation.variables, gql: encryptedGqlString }; // 加密后的字符串作为 variables 的一部分
  return forward(operation).subscribe({})
};

2.main.ts注册加密的拦截器

main.tsVueOioProvider方法内注册,以下代码仅演示了加密的关键配置,其他配置请按原有代码来

VueOioProvider(
  {
    http: {
      url: location.origin + (process.env.BASE_PATH ? `/${process.env.BASE_PATH}` : ''),
      // 此处注册加密的拦截器
      middleware: [ encryptMiddleWare ]
    }
  }
);

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

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

(0)
nation的头像nation数式员工
上一篇 2024年6月19日 pm10:28
下一篇 2024年6月20日 am9:48

相关推荐

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

    使用前提 已经阅读过文档【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…

    2024年7月25日
    1.2K00
  • 使用Mapper方式进行联表查询

    有些业务场景需要查询两张表的数据,这时候就需要用到联表查询。下面将介绍两种方式进行联表查询。 场景:A模型页面,查询条件中包含B模型字段 模型A @Model.model(YesOne.MODEL_MODEL) @Model(displayName = "YesOne", summary = "YesOne") public class YesOne extends IdModel { public static final String MODEL_MODEL = "top.YesOne"; @Field.Integer @Field(displayName = "YesId") private Long yesId; @Field.String @Field(displayName = "名字") private String name; @Field.String @Field(displayName = "科目名字") private String professionalName; @Field(displayName = "关联YesTwo") @Field.many2one @Field.Relation(relationFields = {"yesId"},referenceFields = {"id"}) private YesTwo yesTwo; } 模型B @Model.model(YesTwo.MODEL_MODEL) @Model(displayName = "YesTwo", summary = "YesTwo") public class YesTwo extends IdModel { public static final String MODEL_MODEL = "top.YesTwo"; @Field.Integer @Field(displayName = "科目id") private Long professionalId; @Field.String @Field(displayName = "科目名字") private String professionalName; } 1. 使用in的方式查询 通过B模型的查询条件查询出符合条件的所有数据ID,再根据这个ID去A模型里面查询出所需的数据。 @Function.Advanced(displayName = "查询列表", type = FunctionTypeEnum.QUERY, category = FunctionCategoryEnum.QUERY_PAGE, managed = true) @Function(openLevel = {FunctionOpenEnum.LOCAL, FunctionOpenEnum.REMOTE, FunctionOpenEnum.API}) public Pagination<YesOne> queryPage(Pagination<YesOne> page, IWrapper<YesOne> queryWrapper) { String professionalName = (String) queryWrapper.getQueryData().get("professionalName"); if (StringUtils.isNotBlank(professionalName)) { List<Long> yesTwoId = new YesTwo().queryList(Pops.<YesTwo>lambdaQuery() .from(YesTwo.MODEL_MODEL) .eq(YesTwo::getProfessionalName, professionalName)) .stream().map(YesTwo::getId) .collect(Collectors.toList()); LambdaQueryWrapper<YesOne> wq = Pops.<YesOne>lambdaQuery().from(YesOne.MODEL_MODEL); if (CollectionUtils.isNotEmpty(yesTwoId)) { wq.in(YesOne::getYesId, yesTwoId); } return new YesOne().queryPage(page, wq); } return new YesOne().queryPage(page, queryWrapper); } 2. 使用mapper的方式查询 利用sql的方式去直接查询出结果。使用联表查询的方式查询 @Autowired private YesOneQueryMapper yesOneQueryMapper; @Function.Advanced(displayName = "查询列表", type = FunctionTypeEnum.QUERY, category = FunctionCategoryEnum.QUERY_PAGE, managed = true) @Function(openLevel = {FunctionOpenEnum.LOCAL,…

    2024年9月27日
    1.1K00
  • Maven Setting 配置详解

    常用标签概览 servers/server:配置私有仓库用户名和密码进行认证,以 id 进行关联。 mirrors/mirror:配置镜像仓库拉取时的地址源和额外配置。 profiles/profile:配置多个可能使用的镜像仓库。 activeProfiles/activeProfile:配置默认激活的 profile,以 id 进行关联。 Oinone 私有仓库配置 以下配置可以在使用 Oinone 私有仓库的同时,也可以正常使用 aliyun 镜像源。 <servers> <server> <id>shushi</id> <username>${username}</username> <password>${password}</password> </server> </servers> <mirrors> <mirror> <id>shushi</id> <mirrorOf>shushi</mirrorOf> <url>http://ss.nexus.ixtx.fun/repository/public</url> <!– 忽略 https 认证,maven 版本过高时需要配置 –> <blocked>false</blocked> </mirror> </mirrors> <profiles> <profile> <id>shushi</id> <repositories> <repository> <!– 对应 server.id –> <id>shushi</id> <url>http://ss.nexus.ixtx.fun/repository/public</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <!– 对应 server.id –> <id>shushi</id> <url>http://ss.nexus.ixtx.fun/repository/snapshots</url> <releases> <enabled>false</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </pluginRepository> </pluginRepositories> </profile> <profile> <id>aliyun</id> <repositories> <repository> <id>aliyun</id> <url>https://maven.aliyun.com/repository/public</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>aliyun</id> <url>https://maven.aliyun.com/repository/public</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories> </profile> </profiles> <activeProfiles> <!– 使用 shushi 私有仓库 –> <activeProfile>shushi</activeProfile> <!– 使用 aliyun 镜像仓库 –> <activeProfile>aliyun</activeProfile> </activeProfiles> 常见问题 使用 mvn 时无法拉取 Oinone 最新版镜像,提示找不到对应的包 原因:在 Oinone 开源后,oinone-pamirs 内核相关包都被部署到 maven 中央仓库,但由于其他镜像仓库的同步存在延时,在未正确同步的其他镜像源拉取时会出现找不到对应的包相关异常。 解决方案:检查 mirrors 中是否配置了 aliyun 镜像源,如果配置了,使用上述 Oinone 私有仓库配置重新配置后,再进行拉取。这一问题是由于 mirrors 配置不当,拦截了所有从 maven 中央仓库拉取的地址替换为了 aliyun 镜像源导致的。

    2025年11月10日
    51700
  • 环境运行时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日
    94600
  • oinoneConsole调试工具使用说明

    oioConsole 一个轻量、针对网页的前端开发者调试面板。 oioConsole 是框架无关的,可以在 Vue、React 或其他任何框架中使用。 功能特性 查看GraphQL的接口请求 快速查看到接口的模型和方法 格式化请求中的GraphQL语句 格式化请求中的响应 支持重试请求 支持跳转到oinone管理后台的调试页面进一步查看接口 【oinone前端6.4.0版本开始支持】 提供快捷文档和工具的跳转链接 详情可参考下方的截图。 使用方式 用浏览器环境的前端工程都可以使用,不限于oinone前端 直接插入到 HTML <!– 根据环境条件引入 oioConsole调试控制台 –> <% if (process.env.NODE_ENV === 'development') { %> <script src="https://pamirs.oss-cn-hangzhou.aliyuncs.com/oinone/oinoneconsole/latest/oioconsole.min.js"></script> <script> const mode = localStorage.getItem('mode') // 开发模式下打开控制台,不需要的可以删掉 if (mode === 'dev') { new window.OioConsole({ // network: { // maxNetworkNumber: 100, // 最多显示多少条网络请求 // longRequestTime: 400, // 单位:毫秒ms,超过多少毫秒的请求会显示为长请求 // } }); } </script> <% } %> 进阶用法 可以根据cross-env插件自定义其他环境变量来判断是否需要加载调试工具

    2025年12月24日
    41800

Leave a Reply

登录后才能评论