API接口身份验证方案设计 - TFdream/blog GitHub Wiki
Http Basic Authentication是一种比较简单的身份认证方式。 在 Http 请求Header 中添加键值对 Authorization: Basic xxx,其中xxx 是 base64(username:passowrd)。 例如 username 为 zmk ,password 为 123456,请求则如下
GET /auth/basic/ HTTP/1.1
Host: xxxxx
Authorization: Basic em1rOjEyMzQ1Ng==
而 Base64 的解码是非常方便的,如果不使用 Https ,相当于是帐号密码直接暴露在请求中。 但由于有把用户名密码暴露给第三方客户端的风险,在生产环境下被使用的越来越少。因此,在开发对外开放的RESTful API时,尽量避免采用HTTP Basic Auth。
Session就不用多说了,至于分布式Session实现方案 Java中通过Spring Session可以很方便的实现分布式Session管理。
缺点: 对移动端(Android、iOS)不够友好。
逻辑如下:
- 用户登录成功返回一个api_key和api_secret, 客户端将api_secret存在客户端;
- 当要发送请求之前,将所有参数按字典顺序拼接到一起SHA512后得到一个sign;
- 发送请求的时候,则将除去api_key之外的值,以及sign一起发送给服务器端;
- 服务器端首先验证时间戳是否有效,比如是服务器时间戳5分钟之前的请求视为无效;
- 根据请求api_key对应的api_secret验证sign。
算法代码实现如下:
private static final String UTF_8 = "UTF-8";
public String genSignature(Map<String, String> param, String secret, boolean encode) {
Set<String> keysSet = param.keySet();
Object[] keys = keysSet.toArray();
Arrays.sort(keys); //按参数名字典顺序排序
StringBuilder sb = new StringBuilder(1024);
for(int i=0; i<keys.length; i++) {
if(i!=0){
sb.append("&");
}
sb.append(keys[i]).append("=");
String value = param.get(keys[i]);
String valueString = "";
if (null != value) {
valueString = value;
}
if (encode) {
sb.append(urlEncode(valueString));
} else {
sb.append(valueString);
}
}
sb.append(secret);
return DigestUtils.sha512Hex(sb.toString());
}
private String urlEncode(String str) {
try {
return URLEncoder.encode(str, UTF_8);
} catch (UnsupportedEncodingException e) {
throw new IllegalArgumentException("unsupported encoding:"+UTF_8);
}
}
当客户端登录成功之后,给客户端返回一个token,服务器端控制该token的有效期,每次请求都带上该值,然后服务器端做验证。 整体流程如下:
Token机制相对于Cookie机制有如下好处:
- 支持跨域访问: Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提是传输的用户认证信息通过HTTP头传输.
- 更适用于移动应用: 当你的客户端是一个原生平台(iOS, Android等)时,Cookie是不被支持的(你需要通过Cookie容器进行处理),这时采用Token认证机制就会简单得多。
- CSRF:因为不再依赖于Cookie,所以你就不需要考虑对CSRF(跨站请求伪造)的防范。