zoukankan      html  css  js  c++  java
  • web接口服务端鉴权

      对外提供http+json接口,一般需要附带接口鉴权,往往使用的鉴权方案就是秘钥。为啥需要这么麻烦?因为我们不信任网络,人之初,性本恶。

      秘钥是服务端告知调用方的一串字符串,像AB09Eadf之类的随机码。它由服务端告诉调用方,好比我们知道有个亲戚常来串门,那么就给他留一把备份钥匙,这样他随时想来玩就来,没有钥匙的人我们是不给他进门的。

      钥匙自然不能落在陌生人手里,所以不能用明文在网络上传输。钥匙就是一件信物,只有调用方和服务端知道。服务端往往还会要求提供更完整的信息来做签名,比如服务端的接口url,调用方的请求消息体等。它们连同秘钥一起通过MD5加密后作为一个token发往服务端。

      而服务端接口url、调用方的请求内容和秘钥,对服务端来说都是已知的,所以它再去做一个MD5加密,就得到了另一个token。拿服务端的token跟调用方的一比,相同就是鉴权通过,反之不通过。

      下面看下鉴权的实现:

      1、API:

        /**
         * 提供给ngoc退货同步
         *
         * @param timestamp
         * @param sign
         * @param returnOrder
         * @return
         */
        @RequestMapping(value = "/order/status")
        Result returnOrder(@RequestHeader Long timestamp,
                           @RequestHeader String sign,
                           @RequestBody ReturnOrder returnOrder);

      2、Controller做鉴权:

        @Override
        public Result returnOrder(Long timestamp, String sign, ReturnOrder returnOrder) {
            Result result = new Result(0, "success");
            try {
                orderService.signAuth(getUrl(), timestamp, sign, returnOrder.getOrderId(), migu_apiSecret);
                orderService.insertReturnOrder(returnOrder, timestamp);
            } catch (OrderException e) {
                result.setCode(e.getCode());
                result.setMsg(e.getMsg());
            }
    
           return result;
        }
    
    
    
        /**
         * 请求鉴权
         *
         * @param url 服务url
         * @param timestamp 时间戳
         * @param sign 调用方签名
         * @param arg 请求消息体
         * @param apiSecret 秘钥
         * @throws OrderException
         */
        public void signAuth(String url, Long timestamp, String sign, String arg, String apiSecret) {
    
            String seed = url + timestamp + arg + apiSecret;
            String mySign = getSign(seed);
            if (!mySign.equals(sign)) {
                log.error("request sign != md5 sign. request sign is : {}, mySign is : {}", sign, mySign);
                throw new OrderException(1018, "Token鉴权失败.");
            }
    
            long currentTime = System.currentTimeMillis();
            if ((timestamp + expire_second * 1000) < currentTime) {
                log.error("The token has expired.request time is {}, currentTime is : {}", timestamp, currentTime);
                throw new OrderException(1019, "时间戳过期.");
            }
        }

      有了签名,基本上数据的合法性就得到了保障。只要坏人没有秘钥就无法伪造调用方的请求。但坏人依然可以截取调用方的请求,不停的发送给服务端,造成服务端资源紧张、数据错误等不好的结果。

        为了防止同样的请求多次发送,我们往往还要求调用方提供一个唯一的序列号,比如UUID、时间戳之类的。服务端需要再收到请求的第一时间校验该唯一序列号。我们可以通过spring的切面或者拦截器来做,详见springboot拦截器配置、消息头校验、重复请求过滤

  • 相关阅读:
    [编程] 正则表达式
    [游戏] PhysX物理引擎(编程入门)
    [PHP] visitFile()遍历指定文件夹
    [D3D] 用PerfHUD来调试商业游戏
    [C,C++] 妙用0元素数组实现大小可变结构体
    [D3D] DirectX SDK 2006学习笔记1——框架
    [JS] 图片浏览器(兼容IE,火狐)
    [C#(WinForm)] 窗体间传值方法
    [ASP.NET] 提示错误:The server has encountered an error while loading an application during the processing your request
    [JS] 火狐得到文件的绝对路径(暂时的方法)
  • 原文地址:https://www.cnblogs.com/wuxun1997/p/12102220.html
Copyright © 2011-2022 走看看