[TOC] > [参考](https://www.jianshu.com/p/ad410836587a) ## Token&AppKey(APP) 与开放平台认证不同的是 把 AccessKey改为token ## 简要概述 1. 调用接口前,先获取一个全局唯一的令牌(Token) 2. 调用接口时,将 Token 放到 Header 头中 3. 解析 Header 头,验证是否为有效 Token,无效直接返回失败 4. 完成业务逻辑后,将业务结果与 Token 进行关联存储,设置失效时间 5. 重试时不要重新获取 Token,用要上次的 Token ### Token身份验证 1. 用户登录向服务器提供认证信息(如账号和密码),服务器验证成功后**返回Token**给客户端; 2. 客户端将Token保存在本地,后续发起请求时,**携带此Token**; 3. 服务器检查Token的有效性,有效则放行,无效(Token错误或过期)则拒绝。 > **安全隐患**:Token被劫持,伪造请求和篡改参数。 ### Token+AppKey签名验证 (防篡改) 为客户端分配AppKey(密钥,用于接口加密,不参与传输),将AppKey和所有请求参数组合成源串,根据签名算法生成签名值,发送请求时将签名值一起发送给服务器验证。 ### 重放攻击(可选,推荐) timestamp+nonce方案 timestamp:生成当前时间戳 nonce:生成唯一标识符 服务器判断在timestamp的 15分钟内,是否存在nonce,存在则拒绝,不存在则通过,并记录 nonce(可以使用redis的expire,新增nonce的同时设置它的超时失效时间为15分钟 ### 实现 登陆和登出请求 ![97554574-5BB1-48FC-9BAD-4325DF1095B7.png](http://yanxuan.nosdn.127.net/c73227505f3e7c01dffebbd1a58fd59c.png) #### 获取token认证 1. 发送认证信息(如账户密码) 2. 服务端接受认证信息,通过则生成 token,添加 uid 与有效期后存入数据库 2. 客户单接受服务端返回的 token, 并在后续请求中携带 #### 客户端 1. 生成当前时间戳`timestamp=now`和唯一随机字符串`nonce=random` 2. 按照请求参数名的字母**升序排列非空**请求参数(包含token) `stringA="token=token&home=world&name=hello&work=java&timestamp=now&nonce=random";` 3. 拼接密钥SecretKey `stringSignTemp="stringA&token=token";` 4. MD5并转换为大写 `sign=MD5(stringSignTemp).toUpperCase();` 5. 最终请求 `http://api.test.com/test?name=hello&home=world&work=java&timestamp=now&nonce=nonce&sign=sign;` ### 服务端 ![60621CA6-77C7-4E8A-890F-BB0B3C7AAA42.png](http://yanxuan.nosdn.127.net/a45b123832049d24a8380e6c8ab7f614.png)