原文连接: https://learnku.com/laravel/t...
讨论请前往专业的 Laravel 开发者论坛: https://learnku.com/Laravel
你能够已经据说过 JSON Web Token (JWT) 是目前用于保护 API 的最新技术。laravel
与大多数安全主题同样,若是你打算使用它,那颇有必要去了解它的工做原理(必定程度上)。问题在于,对 JWT 的大多数解释都是技术性的,这一点让人很头疼。git
让咱们看下,我可否解释清楚 JWT 是如何在不引发你的注意下保护您的 API !github
某些 API 资源须要限制访问 。例如,咱们不但愿一个用户可以更改另外一个用户的密码。web
这就是为何咱们保护某些资源,使用户在容许访问以前提供他的 ID 和密码——换句话说,咱们对它们进行身份验证。算法
保护HTTP API的困难在于请求是 无状态的 —— API 没法知道是否有两个请求来自同一用户。数据库
那么,为何不要求用户在每次调用 API 时提供其 ID 和密码呢?仅由于那将是可怕的用户体验。json
咱们须要的是一种容许用户仅提供一次其凭证,随后在后续请求中由服务器以另外一种方式标识的方式。安全
为此设计了几种系统,当前的最新标准是 JSON Web Token。服务器
这是一篇 关于该主题的精彩文章 ,它很好地比喻了 JSON Web Token 的工做方式:网络
想象一下你要入住酒店,而不是一个 API 。「Token」是塑料酒店安全卡,可用于进入你的房间和使用酒店设施,但不能进入任何其余人的房间。
当你退房的时候,你交回卡片。这相似于注销。
一般, JSON Web Token 是经过 HTTP 请求头发送的。相似以下:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U
实际上, Token 部分是「Authorization: Bearer」以后的部分,仅是 HTTP 头信息。
在你判定这是难以理解的胡言乱语前,有几件事你很容易注意到。
首先,Token是由三个不一样的字符串组成,以句点分隔。这三个部分是 Base64 编码 后的内容,而且分别对应 Header , Payload 以及 Signature。
// Header eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 // Payload eyJzdWIiOiIxMjM0NTY3ODkwIn0 // Signature dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U
注意: Base64 是一种转换字符串的方法,以确保在跨网络传输期间不会被弄乱。这不是一种加密方式,任何人均可以 轻松解码 以查看原始数据。
咱们能够对这些字符串进行解码,以更好地了解JWT的结构。
如下是 Token 中的已解码 Header 部分。Header 是 Token 的元信息。它并无告诉咱们不少帮助你创建基本理解的知识,所以咱们不会对此进行任何详细介绍。
{ "alg": "HS256", "typ": "JWT" }
Payload 能引发更多的关注。若是你想, Payload 能够包含任何数据,可是若是 Token 的目的是 API 访问身份验证,则能够仅包含用户 ID 。
{ "userId": "1234567890" }
请注意, Payload 不安全 。 任何人均可以解码 Token ,并确切了解 Payload 中的内容。所以,咱们一般会包含一个 ID ,而不是诸如用户电子邮件之类的敏感识别信息。
即便 Payload 是在 API 上识别用户所须要的所有,它也不能提供身份验证的方法。若是其中包含全部内容,则有人能够轻松找到你的用户 ID 并伪造 Token 。
所以,这使咱们进入了 Signature 部分,这是认证 Token 的关键部分。
在解释签名如何工做以前,咱们须要定义什么是哈希算法。
首先,它是一个将字符串转换为称为 Hash 的新字符串的函数。例如,假设咱们要对字符串「Hello, world」进行哈希处理。这是咱们使用 SHA256 哈希算法获得的输出:
4ae7c3b6ac0beff671efa8cf57386151c06e58ca53a78d83f36107316cec125f
哈希的最重要属性是 你没法经过哈希算法来查看 Hash 的原始文本 。
有许多不一样类型的哈希算法,但 SHA256 一般与 JWT 一块儿使用。
换句话说,咱们不能根据上面的散列值算出原始字符串是 Hello,world。哈希很是复杂,以致于没法猜想原始字符串。
回到 JWT 结构,来看一下令牌的第三部分,签名。实际上须要计算:
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), "secret string" );
下面是对这里发生的状况作解释:
首先, HMACSHA256
是哈希函数的名称, 并带有两个参数:要散列的字符串,以及「secret」。
其次,咱们哈希的字符串是 base 64 的编码报头,加上 base 64 的编码有效载荷。
第三, secret 是任意一段字符串,只有服务器知道。
问. 为何在签名散列中包含标头和有效负载?
这确保了签名对于此特定令牌是惟一的。*
问. secret 是什么?
为了回答这个问题,让咱们考虑一下如何伪造令牌。
咱们以前说过,您没法经过查看输出来肯定哈希的输入。可是,因为咱们知道签名包括标头和有效负载,由于它们是公共信息,因此若是您知道哈希算法(提示:一般在标头中指定),则能够生成相同的哈希。
可是只有服务器知道的秘密 不是 公共信息。将其包含在哈希中可防止某人生成本身的哈希来伪造令牌。并且因为散列会掩盖用于建立散列的信息,所以任何人都没法从散列中找出秘密。
将私有数据添加到哈希中的过程称为 salting ,几乎不可能破解令牌。
所以,如今您对令牌的建立方式有了一个很好的了解。您如何使用它来验证您的API?
用户登陆时会生成令牌,令牌会与用户模型一块儿存储在数据库中。
if (passwordCorrect) { user.token = generateToken(user.id); user.save(); }
而后令牌做为authorization
头附加到登陆请求的响应中。
loginController.js
if (passwordCorrect) { user.token = generateToken(user.id); user.save(); res.headers("authorization", `Bearer ${token}`).send(); }
如今,客户端有了令牌,他们能够将其附加到任何未来的请求以身份验证用户。
当服务器收到带有受权令牌的请求时,将发生如下状况:
1.它解码令牌并从有效载荷中提取ID。
2.它使用此ID在数据库中查找用户。
3.它将请求令牌与用户模型中存储的令牌进行比较。若是它们匹配,则对用户进行身份验证。
authMiddleware.js
const token = req.header.token; const payload = decodeToken(token); const user = User.findById(payload.id); if (user.token = token) { // 经过身份认证 } else { // 未经过身份认证 }
若是用户注销,只需删除附加到用户模型的令牌,如今令牌将再也不起做用。用户将须要再次登陆以生成新令牌。
logoutController.js
user.token = null; user.save();
所以,这是关于如何使用 JSON Web 令牌保护 API 的最基本的说明。但愿你不会很头疼。
不过,相关的话题还有不少,因此这里有一些额外的读物:
原文连接: https://learnku.com/laravel/t...
讨论请前往专业的 Laravel 开发者论坛: https://learnku.com/Laravel