EVE Light on Life

API鉴权方式经验总结

一 前言

软件开发发展至今,前后端分离开发模式越来越流行,往往是后端暴露出一组API提供前端调用,后端根据不同的API请求进行不同的操作。不过后端不应该对所有的请求都进行操作,某些敏感的行为如用户数据、计费统计等等要验证请求API用户的合法性。如此,API应提供鉴权机制,防止其他人随意调用。下面总结了几种API鉴权的方式。

二 会话Cookie认证

Cookie一般应用于浏览器,浏览器使用Ajax请求API时会自动带上本地的Cookie,后端服务器根据保存的会话Cookie值判断是否已登录授权的用户。

实现流程:

  1. 前端访问授权资源,后端判断未授权用户,返回未授权状态码。
  2. 前端收到未授权状态码,跳转到登录页面。
  3. 用户输入帐号密码,提交到后端登录服务,后端接收登录请求,设置好会话Cookie,返回登录成功信息。
  4. 前端再次请求授权资源时带上Cookie头部,可正常访问。

对其余客户端IOS,Andriod等不够友好。

使用Cookie不能跨不同的域名。

三 用户Token认证

用户登录之后后端生成一串认证Token,前端请求授权资源API时带上这个Token,使用url参数或者放在请求头部均可。

Token一般有过期时间,超过过期时间则无效,前端需重新获取Token。

后端可根据Token值鉴权用户,并可根据Token获取与用户相关的信息。可将唯一Token值与用户ID关联存在数据库如Redis,也可将用户信息加密写入Token,通过解密再次获取对应的用户。

若Token过期后仍需用户登录获取新Token,体验非常不好,故此类方式一般加入刷新Token的机制,即生成Token同时也生成一个刷新Token,待Token值即将过期时使用刷新Token请求特定API获取更新后的用户Token。

生成用户Token方式很多,下面使用python的一个itsdangerous库实现。

from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from itsdangerous import SigntureExpired, BadSignature

SECRET_KEY = 'u7Ajjdw$1spcD*cD'

userid = '100002'

s = Serializer(SECRET_KEY, expries_in=600)

token = s.dumps({'uid': userid})

try:
    data = s.loads(token):
except SignatureExpired:
    return None # valid token, but expired
except BadSignature:
    return None # invalid token

userid = data['uid']

print(userid)

四 请求参数签名

此类方式一般应用于企业对外暴露给应用开发者使用的API。开发者向API提供者申请时一般会获得App Key和App Secret。

一个简单的签名算法如下:

  1. 将所有请求参数按字母序升序排序。
  2. 将所有请求参数名和参数值连接成一个字符串,如param1=value1&param2=value2..(包含App key)。
  3. 在字符串尾部加上App Secret,并用SHA1或SHA256签名算法计算出二进制值,转为十六进制的字符串。
  4. 请求时将此字符串和其他请求参数一起发给服务器。

后端服务器收到请求通过App key查到到对用App Secret,同时与前端执行相同的前面算法,比较最终的值与请求参数中的签名值是否一致。

五 OAuth2.0鉴权

OAuth是一个开发标准,允许用户授权第三方网站或应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方网站或分享他们数据的内容。

第三方网站或者应用获取到用户信息后一般会保存起来,与用户前端的鉴权仍是采取前面的Cookie或者产生用户Token方式。

关于OAuth2.0的鉴权,这里有一篇文章说的非常仔细: http://blog.arganzheng.me/posts/oauth.html