其他分享
首页 > 其他分享> > API网关验签

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)
}

 

标签:nonce,网关,const,String,timestamp,headers,API,signature,验签
来源: https://www.cnblogs.com/wlong-blog/p/14966731.html