如何加密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项目引入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日
    1.4K00
  • 如何通过 Oineone 平台自定义视图

    在 Oineone 平台上,自定义视图允许用户替换默认提供的页面布局,以使用自定义页面。本文将指导您如何利用 Oineone 提供的 API 来实现这一点。 默认视图介绍 Oineone 平台提供了多种默认视图,包括: 表单视图 表格视图 表格视图 (左树右表) 详情视图 画廊视图 树视图 每种视图都有其标准的 layout。自定义视图实际上是替换这些默认 layout 的过程。 默认的表单视图 layout <view type="FORM"> <element widget="actionBar" slot="actionBar" slotSupport="action"> <xslot name="actions" slotSupport="action" /> </element> <element widget="form" slot="form"> <xslot name="fields" slotSupport="pack,field" /> </element> </view> 内嵌的的表单视图 layout <view type="FORM"> <element widget="form" slot="form"> <xslot name="fields" slotSupport="pack,field" /> </element> </view> 默认的表格 <view type="TABLE"> <pack widget="group"> <view type="SEARCH"> <element widget="search" slot="search" slotSupport="field" /> </view> </pack> <pack widget="group" slot="tableGroup"> <element widget="actionBar" slot="actionBar" slotSupport="action"> <xslot name="actions" slotSupport="action" /> </element> <element widget="table" slot="table" slotSupport="field"> <element widget="expandColumn" slot="expandRow" /> <xslot name="fields" slotSupport="field" /> <element widget="rowActions" slot="rowActions" slotSupport="action" /> </element> </pack> </view> 内嵌的的表格 <view type="TABLE"> <view type="SEARCH"> <element widget="search" slot="search" slotSupport="field" /> </view> <element widget="actionBar" slot="actionBar" slotSupport="action"> <xslot name="actions" slotSupport="action" /> </element> <element widget="table" slot="table"> <element widget="expandColumn" slot="expandRow" /> <xslot name="fields" slotSupport="field" /> <element widget="rowActions" slot="rowActions" /> </element> </view> 左树右表 <view type="table"> <pack title="" widget="group"> <view type="search"> <element slot="search" widget="search"/> </view> </pack> <pack title="" widget="group"> <pack widget="row" wrap="false"> <pack widget="col" width="257"> <pack title="" widget="group"> <pack widget="col"> <element slot="tree" widget="tree"/> </pack> </pack> </pack> <pack mode="full" widget="col"> <pack widget="row"> <element justify="START" slot="actionBar"…

    2024年4月3日
    1.3K00
  • 标品实施:从标品构建到定制(扩展)包的开发

    总体描述 Oinone有一个非常重要的特性:通过平台承载标准化产品(标品)。针对不同客户的个性化需求,不再直接修改标准产品代码,而是以扩展包的形式进行扩展和定制化,通过继承和重写标准产品的能力来满足客户需求。 本文讲解述怎么通过标品构建扩展工程的过程。 构建标品 按照Oinone的规范构建标品工程 构建扩展包 在定制模块中指定上游模块 上游依赖模块upstreams,模块定义如下: @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Module { // 显示名称 @AliasFor("displayName") String value() default ""; // 依赖模块名列表 String[] dependencies() default ModuleConstants.MODULE_BASE; // 上游模块名列表 String[] upstreams() default {}; …… 扩展模块示例 @Component @Module( name = SecondModule.MODULE_NAME, displayName = "DEMO扩展", version = "1.0.0", // 指定上游模块(标品模块,可以为多个) upstreams = DemoModule.MODULE_MODULE, priority = 1, dependencies = {ModuleConstants.MODULE_BASE, CommonModule.MODULE_MODULE, UserModule.MODULE_MODULE, AuthModule.MODULE_MODULE, BusinessModule.MODULE_MODULE, // 上游模块(标品模块,可以为多个) DemoModule.MODULE_MODULE, } ) @Module.module(SecondModule.MODULE_MODULE) @Module.Advanced(selfBuilt = true, application = true) @UxHomepage(@UxRoute(model = WorkRecord.MODEL_MODEL)) public class SecondModule implements PamirsModule { public static final String MODULE_MODULE = "demo_core_ext"; public static final String MODULE_NAME = "DemoCoreExt"; @Override public String[] packagePrefix() { return new String[]{ "pro.shushi.pamirs.second" }; } } application.yml配置文件 pamirs: boot: modules: ….. – demo_core // 加标准工程 – demo_core_ext maven配置 父工程依赖 <dependencyManagement> <dependencies> ….. <dependency> <groupId>pro.shushi.pamirs.demo</groupId> <artifactId>pamirs-demo-api</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency> <dependency> <groupId>pro.shushi.pamirs.demo</groupId> <artifactId>pamirs-demo-core</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency> ….. </dependencies> </dependencyManagement> api子工程加入依赖 <dependency> <groupId>pro.shushi.pamirs.demo</groupId> <artifactId>pamirs-demo-api</artifactId> </dependency> boot子工程加入依赖 <dependency> <groupId>pro.shushi.pamirs.demo</groupId> <artifactId>pamirs-demo-core</artifactId> </dependency> 数据库设置 base数据库要跟标品工程一致 注意事项 标品工程的第三方依赖,在扩展工程都要有,否则启动会报错 扩展模块功能开发 菜单扩展 1、可以按需隐藏标品的菜单; 2、可以根据扩展包的实际情况增加菜单; 模型扩展 1、扩展包可继承标品已有模型; 新增字段、覆盖字段,不继承 2、扩展包可根据实际情况新增自有模型; 函数扩展 1、扩展包可根据实际情况【覆写】标品中的函数; 2、扩展包可根据实际情况【新增】自有函数; 3、扩展包可通过Hook机制实现业务的个性化; 4、扩展包可根据自身业务情况实现标品中的扩展点; 5、……

    2024年6月1日
    2.1K00
  • 集成开放-开放接口如何鉴权加密

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

Leave a Reply

登录后才能评论