虽然本人现在从事前端开发,但是之前一直是 PHP 全栈,所以对前后端鉴权机制也有一定的了解,就找些资料简单记录一下吧。(瞎掰扯~)
HTTP 是无状态的协议(对于事务处理没有记忆能力,每次客户端和服务端会话完成时,服务端不会保存任何会话信息。):每个请求都是完全独立的,服务端无法确认当前访问者的身份信息,无法分辨上一次的请求发送者和这一次的发送者是不是同一个人。所以服务器与浏览器为了进行会话跟踪(知道是谁在访问我),就必须主动的去维护一个状态,这个状态用于告知服务端前后两个请求是否来自同一浏览器,由此产生了很多种鉴权方式。
另外我们要注意区分
Authentication
与Authrization
,一个是认证一个是授权。Authentication
是为了验证你是不是本人,而Authrization
是为了验证你有没有做某件事情的权限。我们分别举三个例子来说明三种情况让大家对认证和授权的关系有更好的理解。
一旦涉及认证授权,必须要考虑的一个问题就是状态管理。所谓的状态管理就是说我们在进行登录之后的一段时间里,不希望每次访问它都需要重新登录。所以开发者必须要考虑怎么样保持用户的登录状态以及设置失效时间。而这个过程需要前后端通力合作来完成。
这种授权方式是浏览器遵守 HTTP 协议实现的基本授权方式,HTTP 协议进行通信的过程中定义了基本认证允许 HTTP 服务器对客户端进行用户身份证的方法。
基本流程
Get /index.html HTTP/1.0
Host: www.google.com
WWW-Authenticate: Basic realm="google.com"
这句话是关键,如果没有客户端不会弹出用户名和密码输入界面,服务器返回的数据大抵如下。HTTP/1.0 401 Unauthorised
Server: SokEvo/1.0
WWW-Authenticate: Basic realm="google.com"
Content-Type: text/html
Content-Length: xxx
pending
状态,当用户输入用户名密码的时候客户端会再次发送请求头带 Authorization
的请求。Base64
加密方式加密,并将密文放入前一条请求信息中,则客户端发送的第一条请求信息则变成如下内容。Get /index.html HTTP/1.0
Host: www.google.com
Authorization: Basic xxxxxxx(base64 密文)
// 加密过程是浏览器默认的行为,不需要我们人为加密,我们只需要输入用户名密码即可。
Authorization
字段后的用户信息取出并解密,将解密后的用户名及密码与用户数据库进行比较验证,如用户名及密码正确,服务器则根据请求,将所请求资源发送给客户端。优点:简单便捷,兼容性好。
缺点:未使用 TLS/SSL 的情况下信息容易泄露,不安全;无法注销,只能关闭浏览器或标签页。
这种授权方式是利用服务端的 Session 和浏览器(客户端)的 Cookie 来实现的前后端通信认证模式。HTTP 协议是一个无状态的协议,服务器不会知道到底是哪一台浏览器访问了它,因此需要一个标识用来让服务器区分不同的浏览器。cookie 就是这个管理服务器与客户端之间状态的标识。
cookie 的原理是,浏览器第一次向服务器发送请求时,服务器在 response 头部设置 Set-Cookie
字段,浏览器收到响应就会设置 cookie 并存储,在下一次该浏览器向服务器发送请求时,就会在 request 头部自动带上 Cookie 字段,服务器端收到该 cookie 用以区分不同的浏览器。
当然,这个 cookie 与某个用户的对应关系应该在第一次访问时就存在服务器端,这时就需要 session 了。另外 cookie 记得设置过期时间,如果不设置过期时间关闭浏览器就会消失,设置过期时间的话会保存在本地磁盘上。服务端也记得配置 seesion,尤其是分布式服务器在鉴权机制上需要考虑 cookie 共享与 seesion 共享等问题。
session 是会话的意思,浏览器第一次访问服务端,服务端就会创建一次会话,在会话中保存标识该浏览器的信息。它与 cookie 的区别就是 session 是缓存在服务端的,cookie 则是缓存在客户端,他们都由服务端生成,是为了弥补 HTTP 协议无状态的缺陷。每当请求到达服务端时会先校验请求中的用户标识是否存在于 session 中,如果有则表示已经认证成功,否则表示认证失败。
基本流程
sessionId(sid)
。优点:简单便捷,浏览器会自动带上;不需要每次都从数据库取数据比对(如果 sid 不存服务器的话);可以方便管理用户注销与登录(删除/添加 session)。
缺点:脱离浏览器没法用,比如移动端、PC端等;session 存储在服务端,增大了服务器的开销;由于 sid 存在服务端,若被人取到 sid 容易受到跨站请求伪造(CSRF)的攻击,我们可以设置 HttpOnly(脚本无法读取保存在本地的 sid,可以防止 XSS 注入后获取 cookie 中的 sid,从而伪造攻击。)、Secure 设置为 true(使用 HTTPS)来提高安全性;在分布式服务器上,需要共享 session 等配置,会限制负载均衡和集群水平拓展的能力。
token 又叫令牌,本质上就是一串无意义的字符串,一般放在请求头里,请求头 key 一般是 Authorization
,当然也可以和服务端约定好自定义成其他的,只要服务端能够从请求头中拿到 token 就好了。
token 认证的出现最大的特点就是让登录认证不再依赖于 cookie 机制了,将 token 放在了请求头里,那些由于 cookie 机制导致的弊端自然就没有了。
Authorization
中。优点:token 认证不局限于 cookie 且不受同源策略的影响,可以指定放在请求头某个字段中,可以给应用程序使用;不使用 cookie,攻击者无法猜到使用的 token 在哪,而且用户的 token 存在本地,只有在提交请求时才会放在请求头某个字段中供服务器读取(类似于获取 Referer 这种,脚本无法读取。),这些就可以一定程度上规避 CSRF 攻击。
缺点:加密解密消耗使得 token 认证比 Session-Cookie 更消耗性能;token 比 sessionId 大,更占带宽;token 需要去数据库中查询用户信息,增大数据库压力。
由于每次请求都要用 token 去数据库中查询用户信息,数据库的压力太大了。如果 token 携带了用户信息,不就不需要每次请求都访问数据库查了嘛,可以直接从 token 中直接解析出用户信息以及用户登录状态进行校验,这就是 JWT。给浏览器返回的 token 是一串带着用户信息的加密字符串。 JWT 全称是 Json Web Token。其实就是特殊的 token,理解起来就是携带着用户信息的 token。所以 JWT 认证和 token 认证本质上是一样的。只不过 token 认证的用户信息是从数据库里查的。而 JWT 认证的用户信息是直接从 token 解析出来的。
Header
Payload
iss (issuer):签发人
exp (expiration time):过期时间
sub (subject):主题
aud (audience):受众
nbf (Not Before):生效时间
iat (Issued At):签发时间
jti (JWT ID):编号
除了官方字段,你还可以在这个部分定义私有字段,比如用户名、用户昵称、权限、部门等等。
注意,JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分。
这个 JSON 对象也要使用 Base64URL 算法转成字符串。
Signature
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
Header、Payload、Signature
三个部分拼成一个字符串,每个部分之间用 .
分隔,就可以返回给用户。 前面提到,Header 和 Payload 串型化的算法是 Base64URL。这个算法跟 Base64 算法基本类似,但有一些小的不同。
JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 http://api.example.com/?token=xxx
)。Base64
有三个字符 +
、/
、=
,在 URL 里面有特殊含义,所以要被替换掉:=
被省略、+
替换成 -
,/
替换成 _
。这就是 Base64URL 算法。
了解以上内容后我们简单说一下流程
Authorization
中,当然你也可以放到 cookie 中,但是这样不能跨域。Authorization: Bearer <token>
OAuth 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是 OAuth 的授权不会使第三方触及到用户的帐号信息(如用户名与密码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此 OAuth 是安全的。 同时,任何第三方都可以使用 OAuth 认证服务,任何服务提供商都可以实现自身的 OAuth 认证服务,因而 OAuth 是开放的。我们常见的提供 OAuth 认证服务的厂商有支付宝、QQ、微信、微博、Github等。 OAuth 协议又有 1.0 和 2.0 两个版本。相比较 1.0(存在严重安全漏洞已停用),2.0 版整个授权验证流程更简单更安全,也是目前最主要的用户身份验证和授权方式。
基本流程
RequestToken URL
发起请求。UserAuthorization URL
发起请求并在请求中携带上一步服务提供商颁发的未授权的 oauth_token 与 oauth_token_secret。AccessToken URL
发起请求,将上步授权的 RequestToken 换取成 AccessToken 与 RefreshToken。OAuth2.0 提供了四种授权模式,开发者可以根据自己的业务情况自由选择。
一文详解前后端鉴权