• API网关验签


    在前后端开发的过程中,我们一般在请求头中添加一些信息来保证验证请求身份,这里涉及到四个字段值:

    appId: 软件Id

    nonce:随机字符串

    timestamp:时间戳

    signature:签名

    代码如下:

    @Component
    public class CommonApiAuthGatewayFilterFactory extends AbstractGatewayFilterFactory<Object> {
    
        @Override
        public GatewayFilter apply(Object config) {
            return (exchange, chain) -> {
                ServerHttpRequest request = exchange.getRequest();
                String httpMethod = request.getMethodValue();
                String httpUri = request.getURI().getPath();
                //特定请求不进行验签
                if (httpUri.contains("/v2/api-docs")){
                    return chain.filter(exchange.mutate().request(request.mutate().build()).build());
                }
    
                HttpHeaders headers = request.getHeaders();
                String signature = headers.getFirst(Constant.SIGNATURE);
                String nonce = headers.getFirst(Constant.NONCE);
                String appId = headers.getFirst(Constant.APP_ID);
    
                if (StringUtils.isAllBlank(signature, nonce, headers.getFirst(Constant.TIMESTAMP))) {
                    return ApiAuthUtils.checkSign(exchange, WrapMapper.illegalArgument("signature|nonce|timestamp不能为空"), HttpStatus.BAD_REQUEST);
                }
                long timestamp = Long.parseLong(headers.getFirst(Constant.TIMESTAMP));
    
                // 验证如果传过来的时间戳超过1分钟,直接返回false
                if ((System.currentTimeMillis() - timestamp) / 1000 > 60) {
                    return ApiAuthUtils.checkSign(exchange, WrapMapper.wrap(403, "timestamp overtime"), HttpStatus.FORBIDDEN);
                }
    
                boolean result = CryptUtils.validateSignature(appId, timestamp, nonce, httpMethod, httpUri, signature);
                if (!result) {
                    return ApiAuthUtils.checkSign(exchange, WrapMapper.wrap(403, "Forbidden"), HttpStatus.FORBIDDEN);
                }
    
                Builder mutate = request.mutate();
                return chain.filter(exchange.mutate().request(mutate.build()).build());
            };
        }
    }

    验签算法:

     public static boolean validateSignature(String appId, long timestamp, String nonce, String httpmethod,String httpurl, String signature) {
            String str = appId + "|" + nonce + "|" + timestamp + "|" + httpmethod.concat("|").concat(httpurl);
            String encryptBASE64 = encryptBASE64(sha256(str.getBytes()));
            logger.debug("signature: {}, encryptBASE64: {}", signature, encryptBASE64);
            return Arrays.equals(encryptBASE64.getBytes(), signature.getBytes());
        }

    前端在发送请求时也需要在请求头加入对应信息,如:

    request.interceptors.request.use(config => {
      const token = storage.get(ACCESS_TOKEN)
      if (token) {
        config.headers['Access-Token'] = token
      }
      const url = config.url.split('?')[0]
      const appId = '123456789'
      const timestamp = new Date().getTime()
      const nonce = generateNonce(timestamp)
      const signature = generateSignature(appId, timestamp, nonce, config.method.toUpperCase(), url)
      config.headers.appId = appId
      config.headers.signature = signature
      config.headers.nonce = nonce
      config.headers.timestamp = timestamp
      return config
    }, errorHandler)
    
    export const generateSignature = (appId, timestamp, nonce, httpMethod, httpURL) => {
      const str = appId + '|' + nonce + '|' + timestamp + '|' + httpMethod + '|' + httpURL
      let result = SHA256(str)
      if (result) {
        result = strToBase64(result)
      }
      return result
    }
    
    export const generateNonce = (theServerTime) => {
      const randomNumber = []
      for (let i = 0; i < 8; i++) {
        const oneRandom = random(-128, 127)
        randomNumber.push(oneRandom)
      }
      let timeStamp = Math.floor(new Date().getTime() / 60000)
      if (theServerTime !== 0) {
        timeStamp = Math.floor(theServerTime / 60000)
      }
    
      const nt = []
      nt[3] = timeStamp & 0xff
      nt[2] = (timeStamp >> 8) & 0xff
      nt[1] = (timeStamp >> 16) & 0xff
      nt[0] = (timeStamp >> 24) & 0xff
      for (let x = 0; x < nt.length; x++) {
        randomNumber.push(nt[x])
      }
    
      return bytesToBase64(randomNumber)
    }
  • 相关阅读:
    [Tutorial] How to check and kill running processes in Ubuntu
    [Tutorial] Getting started with Gazebo in ROS
    Linux基础命令
    Linux安装系统
    vue 前后端数据交互问题解决
    如何在cmd中启动MongoDB服务器和客户端
    selenuim模块的使用 解析库
    beautifhulsoup4的使用
    浅谈scrapy框架安装使用
    自动登录 点赞 评论 抽屉网
  • 原文地址:https://www.cnblogs.com/wlong-blog/p/14966731.html
Copyright © 2020-2023  润新知