本次的直接起因是第三方那边接入系统后端引起的,第三方方觉得认证要过期比较麻烦,而且要用账号密码去调登录接口去刷token,设计不合理。
客观来说:
凭本人使用过其它开放平台来说确实有些不一样。 常见的一些开放平台,有带web的,一般web能看到的接口,在你想进行一些二次开发时调用他们的接口是另外一套接口,web显示的一般会在包一层(github web端直接返回的html)。另外调用他们的接口的认证方式也不是像在web端那样,走传统的账号密码登录的方式。
主观来说:
有没有必要去做,还是要看我们系统的定位,如果想像一些开放平台一样对外提供服务,那么看来是有必要的,如果最终只是内部用,那么是没必要的。这些认证也往往考虑计费模式。另外过期是合理的,可能也只是刷 token的方式有点不合适。
Token auth
用户输入账号密码校验成功后,服务端返回token,以后客户端就可以用token去调接口,token过期或者永久都可以,看业务。
常见的实践有jwt等
我们目前还是用的sso-token,会2个月过期,过期后需要调用方使用账户密码主动调用sso登录接口去更新token。
优点:
1.不用改动或改动较小
缺点:
1.安全性,后端和前端共有接口及认证方案,客户能直接登陆我们的pegasusu配置平台。
Hmac
一般用户在个人主页申请appid,secret。然后调用对话系统后端接口时对接口进行签名。
参数名 | 描述 | ||
appid | 每个项目分配的appid | ||
secret | 每个项目分配的secret,随机字符串 | ||
sign | 签名 | ||
timestamp | unix时间戳,调用方服务器的时间戳 |
比如访问创建subuser接口 /v1/applications/7296/subusers
现在变为 /v1/applications/7296/subusers?appid=7296×tamp=12121212&sign=adjiaofda
sign=md5(str(appid)+str(timestamp)+secret) 取一半 前64位
对话系统后端根据appid找到对应的secret,对客户传来的appid,timestamp,secret进行同样的计算,然后比较sign是否一致。
一个具体的例子https://www.xfyun.cn/doc/asr/voicedictation/API.html#%E6%8E%A5%E5%8F%A3%E8%B0%83%E7%94%A8%E6%B5%81%E7%A8%8B
func assembleAuthUrl(hosturl string, apiKey, apiSecret string) string {ul, err := url.Parse(hosturl)if err != nil {fmt.Println(err)}//签名时间date := time.Now().UTC().Format(time.RFC1123)//参与签名的字段 host ,date, request-linesignString := []string{"host: " + ul.Host, "date: " + date, "GET " + ul.Path + " HTTP/1.1"}//拼接签名字符串sgin := strings.Join(signString, "\n")//签名结果sha := HmacWithShaTobase64("hmac-sha256", sgin, apiSecret)//构建请求参数 此时不需要urlencodingauthUrl := fmt.Sprintf("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apiKey,"hmac-sha256", "host date request-line", sha)//将请求参数使用base64编码authorization:= base64.StdEncoding.EncodeToString([]byte(authUrl))v := url.Values{}v.Add("host", ul.Host)v.Add("date", date)v.Add("authorization", authorization)//将编码后的字符串url encode后添加到url后面callurl := hosturl + "?" + v.Encode()return callurl}
优点:
1.验证请求者的身份 签名可以确保请求是由某个具有有效访问密钥的用户或服务发起。
2.保护传输中的数据,防止非法篡改 若请求在传输过程中遭到非法篡改,由于第三方无法对篡改后的请求进行计算,得到新的认证字符串(Authorization),服务收到请求后认证字符串匹配将失败,因此身份校验无法通过。
3.防止重放攻击 认证字符串(Authorization)都具有指定的有效时间。如请求被截获,第三方无法在有效时间之外重放请求。
4.纯后端接口认证,登不了我们的web
缺点:
1.对于开发者来说,也是很不友好的,在组织签名的那些HTTP报文的时候,各种,URLEncode和Base64,还要对Query的参数进行排序,然后有的方法还要层层签名,比较容易出错
2.没有过期一说
参考:
https://cloud.baidu.com/doc/Reference/s/Njwvz1wot
http://static.kancloud.cn/h360881323/payment_api/1153973
oauth 2.0
什么是oauth2.0 http://www.ruanyifeng.com/blog/2019/04/oauth_design.html
oauth2.0有四种授权方式,这里我们选择其中的凭证式
https://oauth.b.com/token? grant_type=client_credentials& client_id=CLIENT_ID& client_secret=CLIENT_SECRET
client_id 类似于 appid
client_secret 类似于 secret 私有的
oauth与其它不同的地方在于定义了授权服务,资源服务,客户端不同的角色,强调必须使用https。
请求流程大概就是去授权服务器获取accessToken,然后用accessToken去获取资源。accessToken过期后需要再去刷新。原oauth2.0的定义是还会有一个refresh token,用这个去刷新获得新的accessToken。这里简化后,就用上面的方式刷新即可。
优点:
1.accessToken过期机制,不用担心泄漏
2.强制使用https避免中间人攻击
缺点:
1.实现复杂,工作量比较大,需要增加token有关的一组接口
2.oauth2.0没有统一的协议,各家实现不一
这里有个问题,不管哪种都有类似于secret的东西,如果这个泄漏了,那不是随意调用了就?
A: 一个防止这个的方法就是加ip白名单,只有客户指定的某些出口ip可以去刷新token这个事情,这样即使泄漏,没有ip白名单他也不能去操作刷新token,见微信公众平台。
在oauth2.0里,另外也建议去客户业务方去做个专门的刷新token的服务,去和业务解耦,这里我理解 因为业务服务变动比较频繁,需要频繁的设置白名单,同时比较高权限的人去维护这个授权服务,降低泄漏的风险。
参考:
https://ai.baidu.com/ai-doc/REFERENCE/Lkru0zoz4
https://open.dingtalk.com/document/orgapp-server/obtain-the-access_token-of-an-internal-app
https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Getting_Started_Guide.html
https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html
Http Basic auth 和 Key auth
二者类似
大概就是给每个项目分配一个key,secret,调用接口时做一些编码传过来,服务端解码然后验证。
目前一些开放平台最常见的也就是hmac签名和oauth2.0的方式。另外secret的泄漏也是需要客户测去防范。平台方的ip白名单,以及客户端侧自己将授权和业务隔离 是比较好的方法。