基于Token的身份验证——JWT
1、JWT是什么
JSON Web Token (JWT) 使用一种基于签名的机制来确保数据的完整性和安全性,以便能够验证其真实性。JWT 并不是加密的,而是使用签名来验证其内容是否被篡改。下面我将解释 JWT 是如何工作的以及为什么它们通常是安全的。
JWT 通常由三部分组成:Header、Payload 和 Signature。
-
Header(头部):Header 包含有关 JWT 的元数据和签名算法的信息。这部分通常是 Base64 编码的,但它并不是加密的,只是编码,所以可以很容易地被解码。
-
Payload(荷载):Payload 包含有关用户或实体的声明和数据。这部分通常是 Base64 编码的,但它并不是加密的,只是编码,所以可以很容易地被解码。
-
Signature(签名):Signature 是对 Header 和 Payload 的签名。这部分通常是使用签名算法(例如 HMAC SHA256)和密钥(通常被称为 JWT secret)对 Header 和 Payload 数据签名而生成的,这个签名用于验证 JWT 的完整性和真实性。
JWT形式如下:
A.B.C
1.1 怎样生成A?
header格式为:
{ "typ": "JWT", "alg": "HS256" }
它就是一个json串,两个字段是必须的,不能多也不能少。alg
字段指定了生成C的算法,默认值是HS256
将header用base64编码,得到A
通常,JWT库中,可以把A部分固定写死,用户最多指定一个alg
的取值
1.2 怎样计算B?
根据JWT claim set[用base64]加密得到的。claim set是一个json数据,是表明用户身份的数据,可自行指定字段很灵活,也有固定字段表示特定含义(但不一定要包含特定字段,只是推荐)。
这里偷懒,直接用php中的代码来表示claim set了,重在说明字段含义:
$token = array( "iss" => "http://example.org", #非必须。issuer 请求实体,可以是发起请求的用户的信息,也可是jwt的签发者。 "iat" => 1356999524, #非必须。issued at。 token创建时间,unix时间戳格式 "exp" => "1548333419", #非必须。expire 指定token的生命周期。unix时间戳格式 "aud" => "http://example.com", #非必须。接收该JWT的一方。 "sub" => "jrocket@example.com", #非必须。该JWT所面向的用户 "nbf" => 1357000000, # 非必须。not before。如果当前时间在nbf里的时间之前,则Token不被接受;一般都会留一些余地,比如几分钟。 "jti" => '222we', # 非必须。JWT ID。针对当前token的唯一标识 "GivenName" => "Jonny", # 自定义字段 "Surname" => "Rocket", # 自定义字段 "Email" => "jrocket@example.com", # 自定义字段 "Role" => ["Manager", "Project Administrator"] # 自定义字段 );
JWT遵循RFC7519,里面提到claim set的json数据中,自定义字段的key是一个string,value是一个json数据。因此随意编写吧,很灵活。
个人初学,认为一个最基本最简单最常用的claim set为:
$token=array( "user_id" => 123456, #用户id,表明用户 "iat" => 1356999524, #token发布时间 "exp" => 1556999524, #token过期时间 );
将claim set用base64编码得到B
,学名payload
1.3 怎样计算C?
服务器使用 JWT 的头部 (Header) 和负载 (Payload) 数据,以及一个密钥(通常被称为 JWT secret,其实就是一个字符串)作为输入,使用指定的签名算法(例如 HMAC SHA256,其实是用header中指定的算法)来生成 Signature。生成的 Signature 会被附加到 JWT 的末尾,形成完整的 JWT 令牌。
客户端收到 JWT 后,可以使用相同的密钥和相同的签名算法来验证令牌的完整性。它会提取 Header 和 Payload 数据,然后使用相同的密钥和签名算法重新计算 Signature。如果新生成的 Signature 与 JWT 中的 Signature 相匹配,那么说明令牌没有被篡改。(非必需步骤)
好了,现在A.B.C
就是生成的token了。这种签名机制确保了 JWT 在传输过程中的完整性和真实性,防止了篡改令牌数据的尝试。因此,保护 JWT 密钥的安全性非常重要,以防止未经授权的签名操作。如果 JWT 用于身份验证和授权,建议密钥的生成和存储要得到妥善处理,以确保安全性。
2、JWT 的工作流程
JWT 的工作流程如下:
- 服务器在创建 JWT 时,使用签名算法和密钥对 Header 和 Payload 进行签名生成 Signature。
- 客户端收到 JWT 后,可以对 Header 和 Payload 进行解码,但无法修改 Signature,因为它需要服务器的密钥来重新生成。如果其中任何一部分被篡改,Signature 将无效。
- 当客户端将 JWT 发回服务器时,服务器使用相同的密钥和签名算法重新计算 Signature来验证 JWT 的 Signature,以确保它没有被篡改。
这意味着,JWT 是安全的,只要密钥保持机密并且只有服务器能够生成有效的签名。但是,如果密钥被泄露或者服务器的签名算法存在漏洞,那么攻击者可能会创建伪造的 JWT 或者解密其中的数据。因此,保护密钥的安全性非常重要。
3、客户端怎样使用token
可以放到HTTP请求的请求头中,通常是Authorization
字段。
也有人说放到cookie。不过移动端app用cookie似乎不方便。
token应用流程:
- 初次登录:用户初次登录,输入用户名密码
- 密码验证:服务器从数据库取出用户名和密码进行验证
- 生成JWT:服务器端验证通过,根据从数据库返回的信息,以及预设规则,生成JWT
- 返还JWT:服务器的http response中将JWT返还
- 带JWT的请求:以后客户端发起请求,http request header的Authorization字段都要有值,为JWT