跨域认证

物联网服务离不开身份认证,常规的方法是:

  1. 用户发送账号密码
  2. 服务器验证通过后,在当前session中保存登录记录,包括用户信息、登录时间等
  3. 服务器向用户返回一个session_id,写入用户的cookie
  4. 之后用户每次访问都带上该cookie,服务器根据cookie携带的session_id进行身份识别

该方法需要服务器保存用户登录信息,如果服务器需要集群,或者是跨域,就必须将session共享。当然,可以考虑将session数据持久化,让服务向持久层请求数据。
但是这样的方法会给服务器或持久层带来压力,当用户量很大的时候,需要存储的数据会很大,给内存带来压力。

另一种解决方案是使用token,由客户端保存服务器分发的token,在请求服务时携带token,由服务端使用对应的算法验证该token是否合法,如果通过则继续提供服务。

JWT就属于使用token方案的一个代表技术。

JWT概述

JWT(JSON Web Token)的原理是:服务器通过第一次认证后,生成一个JSON对象作为token返回给用户,以后的每次请求都携带该JSON对象用于鉴权,而服务器无需再保存session数据,完全靠该JSON对象验证身份。

由于是由用户存储该JSON对象,为了防止篡改,服务器在其后面会加上签名。

JWT结构

JWT由三部分组成,彼此之间使用.分隔,并且无换行:

  1. Header:头部
  2. Payload:负载
  3. Signature:签名

Header描述JWT的 元数据,包括签名算法和token的类型

1
2
3
4
{
"alg": "HS256",
"type": "JWT"
}

然后使用Base64进行编码

Payload存放实际需要传递的数据,有如下几个官方字段供选用:

  • iss (issuer):签发人
  • exp (expiration time):过期时间
  • sub (subject):主题
  • aud (audience):受众
  • nbf (Not Before):生效时间
  • iat (Issued At):签发时间
  • jti (JWT ID):编号
    当然也可以定义私有字段,但是注意JWT默认不加密,请不要放秘密信息在这里。
1
2
3
4
5
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}

然后同样使用Base64进行编码

Signature是对前两个部分的签名,以防止数据篡改:

1
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

三个部分都计算完成后,将其拼接成一个完整的字符串,中间由.连接,然后就可以返回给用户。

JWT的使用

服务端生成JWT数据后,用户每次请求就都需要携带该JSON数据。
例如可以将其放在cookie中自动发送,但是这样不能进行跨域,因此更一般的做法是将其作为http请求的Authorization字段进行发送

JWT的特点

  • JWT默认不加密,在未加密的情况下,不要将秘密放在JWT中
  • JWT可以在生成初始token后再使用密钥进行一次加密
  • JWT无法中途销毁,在其有效时间之前一直保持有效
  • JWT包含验证信息,要避免泄露,否则他人可以直接获得其所有权限,所以应该使用https进行传输