关于开发api开放平台过程中的知识
这是在开发api开放平台中用到的一些新知识,这些概念对于初学者来说确实比较陌生,因此这里写一篇详细的开发过程和涉及到的知识。
API签名认证
在开发API开放平台的时候,需要管理API的调用,这里会涉及到一个问题,就是必须对api的发送作出限制,限制用户的调用,限制调用的次数,判定调用者的身份是否确实为该用户本身(中间人拦截再重复调用)。因此使用到了叫API签名认证的技术,本文对这个技术的学习过程作出一些总结。
具体实现方法
签名认证本质上就是后端去校验前端传来的签名,具体实现的方法第一种是通过请求头 request header来实现,首先我们必须在用户的表上添加属性 assessKey和secretKey,这个是两个标识,至于为什么要两个属性可以参考一下登陆系统要用的用户名和密码。
当然这两个key肯定不能写死,这里为了先跑通整个流程,先写死了,最后应该是在注册的时候生成?这个还需要再思考一下。
接下来我们在调用接口的时候传入这两个key,打个断点调试一下,可以得到结果:
进入到这个判断,就说明校验key的逻辑完成了✅。
思考
这种方法是一种方法,但是咱们来想一想,这样子做的话,前端在调用api发请求的时候也将assessKey和secretKey发送到了后端,这样子校验是非常危险的,因为同时将两个Key暴露在了网络传输当中,如果前端发送的请求被拦截,或者攻击者重复发送请求,都可能成功调用起后端接口,所以这种方法还需要进一步提升,提升的方法可以参考登录注册的方法,进行加密算法。
进一步的改进
因为直接将key放在请求头在服务器之间传递是非常危险的,我们必须给密钥做加密。这里我的做法是根据密钥生成一个sign,再去跟后端比对。
签名sign的生成
签名的生成过程:用户参数 + 密钥 => 签名生成算法(MD5,HMac,Sha1) => 不可解密的值
举个例子,abc+user1=>afasfasnwg,这个就是个乱码了,即使请求被拦截,抓出来也看不出这是个什么。接下来还有一个问题,就是怎么防止请求重放,这个可以用到时间戳和加入随机数来实现,后端存储随机数,加入时间戳限制来刷新随机数,检验有效期。
开始coding😭
首先我们理一理请求头里都有些什么元素:
- assessKey
- serectKey 这个一定不能传出去,所以不在请求头里🌟🌟🌟‼️
- nonce 随机数
- body 用户参数
- timestamp 时间戳
- sign 签名
确定之后就可以写生成签名的函数和生成请求头函数了
/** |
这里建议把签名生成单独拿出来做工具类,这样校验的时候也方便,调用接口的签名生成之后,就要去服务端校验接口,校验接口的思路就很简单了,取出请求头中的nonce, timestamp 和 body,数据库查表找到secretKey,调用签名生成工具生成服务端签名,和前端传来的签名比对,比对不匹配就抛出异常。写完之后打好断点调试一下:
这里看到成功进入判断逻辑,两边的签名是一致的,到这里签名认证环节就结束了。
starter开发
在开发API开放平台的时候,由于我们需要让用户调用接口,而用户不应该自己去使用 调用第三方接口的库,这对于开发者来说太麻烦,平台展现给开发者的情况应该是:开发者应该只需要关心自己要用什么接口,传什么参数,密钥是什么等等,所以我们需要开发一个便于开发者使用的sdk。
首先我们来开发starter,starter是个什么东西呢,我的理解呢就是一个工具包,跟jar包有那么一点像,但是它可以直接在application.yml中配置,方便自动创建出这么一个客户端之类的东西
开发starter
首先呢我们新建springboot项目,引入依赖lombok和spring configuration processor,进入pom.xml文件中删除build标签下所有内容,因为我们不需要将它构建成一个可运行的springboot项目,随后删除主类,因为我们不需要启动这个项目,我们只是需要做一个工具包出来。这里有一个小小的坑,就是依赖要引入一下spring web的依赖,如果不引入的话呢,生成不了resource目录和application.yml文件,但是我看别人好像没有这个问题,当然目的就是为了生成resource目录。
前置工作做完之后就是写你自己的配置
package com.si1v3r.si1v3rapiclientsdk; |
这里注意要引入你相对应的客户端和对象,比如我这里就是Si1v3rApiClient,如果有必要的依赖和工具类也要一并加入进来,做好之后在resource目录下新建一个META-INF文件夹,新建spring.factories文件,加入配置路径
#spring boot starter |
这里的路径是指定你的配置类的路径,这些做完以后就可以去生命周期里install了,这样会生成一个包,同时我们要记住这个sdk项目的groupId,artifactId, version这三个信息,到虚拟调用api去导入
这里能这么导入的原因其实是因为生成的maven包存在了本地的mvn仓库里,所以本地能直接导入,如果要想让其他人也能用,要上传到远程的mvnrepository。导入成功后我们进入application.yml,发现可以直接配置了(nb。
这里配置完两个密钥,就可以去写单元测试了
恶心的bug
但是第一次测的时候会出现一个hutools连接拒绝的问题,然后我们能发现项目的启动端口变成sdk的端口了(。这个问题相当逆天,报错图用一下别人的:
这里我还发现项目启动端口变成sdk里默认的端口8080了,这就很蛋疼,说明我们一开始引入spring web的依赖的思路是不行的,一旦引入spring web会导致对端口进行配置,即使我后来删了application.yml还是更改了,很恶心。最后解决方法还是得一开始不引入这个spring web,自己去新建resources目录和META- INF目录,然后流程不变再生成导入一次,最后打开项目端口,运行单元测试,能发现测试终于过了T_T。