最近我开始使用基于JWT的身份验证。用户登录后,会生成一个用户令牌 " eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"
它由三个部分组成,每个部分用点(。)分隔。第一部分是Base64编码的标题。解码后我们会得到类似的东西 { " alg":" HS256",//使用的算法 " typ":" JWT" }
第二部分是声明和Base64编码。解码后我们会得到类似的东西 { " sub":" 1234567890", "姓名":" John Doe", " admin":是的 }
第三部分是签名,用
生成HMACSHA256( base64UrlEncode(header)+"。" + base64UrlEncode(有效载荷), 秘密base64编码 )
现在这个密钥是什么以及如何生成这个密钥?
我尝试了一些在线生成器,例如" http://kjur.github.io/jsjws/tool_jwt.html" 但是得到很多帮助。
答案 0 :(得分:32)
Json Web令牌由三部分组成。标头,有效载荷和签名现在,标头只是有关令牌本身的一些元数据,有效载荷是我们可以编码为令牌的数据,也就是我们真正想要的任何数据。因此,我们要在此处编码的数据越多,JWT越大。无论如何,这两个部分只是纯文本,将被编码,但不会被加密。
因此任何人都可以对其进行解码和读取,我们无法在此处存储任何敏感数据。但这根本不是问题,因为在签名的第三部分中,事情确实变得很有趣。签名是使用标头,有效负载和服务器上保存的机密创建的。
然后将整个过程称为签署Json Web令牌。签名算法采用标头,有效负载和秘密来创建唯一的签名。所以只有这些数据加上秘密才能创建此签名,好吗? 然后,这些签名连同标头和有效负载一起组成JWT, 然后将其发送给客户端。
一旦服务器接收到JWT来授予对受保护路由的访问权,它就需要对其进行验证,以确定用户是否确实是他声称的身份。换句话说,它将验证是否没有人更改令牌的标头和有效载荷数据。同样,此验证步骤将检查是否没有第三方实际更改Json Web令牌的标头或有效载荷。
那么,此验证实际上如何工作?好吧,这实际上很简单。收到JWT后,验证将获取其标头和有效负载,以及仍保存在服务器上的机密信息,基本上会创建一个测试签名。
但是第一次创建JWT时生成的原始签名仍然在令牌中,对吗?这就是验证的关键。因为现在我们要做的就是将测试签名与原始签名进行比较。 并且,如果测试签名与原始签名相同,则表示有效负载和标头尚未修改。
因为它们已经被修改,所以测试签名必须是不同的。因此,在这种情况下,数据没有发生变化,我们可以对用户进行身份验证。当然,如果两个签名 实际上是不同的,那么,这意味着有人篡改了数据。 通常通过尝试更改有效负载。但是,操纵有效载荷的第三方当然不能访问该秘密,因此它们无法签署JWT。 因此,原始签名将永远不会对应于被操纵的数据。 因此,在这种情况下,验证将始终失败。这是使整个系统正常工作的关键。是让JWT变得如此简单的魔力, 但也非常强大。
现在让我们对nodejs进行一些实践:
配置文件非常适合存储JWT SECRET数据。使用标准的HSA 256加密进行签名,密钥长度至少应为32个字符,但越长越好。
config.env:
JWT_SECRET = my-32-character-ultra-secure-and-ultra-long-secret
//after 90days JWT will no longer be valid, even the signuter is correct and everything is matched.
JWT_EXPIRES_IN=90
现在使用命令安装JWT
npm i jsonwebtoken
用户注册后为其传递JWT令牌,以便他可以保持登录状态并获得资源访问权限的示例。
exports.signup = catchAsync(async (req, res, next) => {
const newUser = await User.create({
name: req.body.name,
email: req.body.email,
password: req.body.password,
passwordConfirm: req.body.passwordConfirm,
});
const token = jwt.sign({ id: newUser._id }, process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRES_IN,
});
res.status(201).json({
status: 'success',
token,
data: {
newUser,
},
});
});
我认为,请勿寻求第三方的帮助来生成您的超级秘密密钥,因为您不能再说它是秘密了。只需使用键盘即可。
答案 1 :(得分:25)
用于签署JWT的算法(HS256
)意味着该秘密是发送方和接收方都知道的对称密钥。它是在带外协商和分发的。因此,如果您是令牌的预期收件人,则发件人应该已向您提供带外秘密。
如果你是发件人,你可以使用任意字节串作为秘密,可以生成或故意选择。您必须确保向带外的目标收件人提供秘密。
对于记录,JWT中的3个元素不是base64编码的,而是base64url编码的,它是base64编码的变体,可以产生URL安全值。
答案 2 :(得分:6)
您可以编写自己的发电机。密钥本质上是一个字节数组。确保转换为字节数组的字符串是base64编码的。 在Java中你可以做这样的事情。
String key = "random_secret_key";
String base64Key = DatatypeConverter.printBase64Binary(key.getBytes());
byte[] secretBytes = DatatypeConverter.parseBase64Binary(base64Key);
答案 3 :(得分:0)
密钥与标头和有效载荷结合在一起以创建唯一的哈希。只有拥有密钥,您才能验证此哈希。
您可以选择一个好的长密码。或者您可以从this之类的网站生成它。
示例(但现在不要使用此示例):
8Zz5tw0Ionm3XPZZfN0NOml3z9FMfmpgXwovR9fp6ryDIoGRM8EPHAB6iHsc0fb
答案 4 :(得分:0)
密钥到底是做什么的,您到目前为止可能已经知道。 它基本上是HMAC SH256(安全哈希)。 秘密是对称密钥。
使用您可以生成,重新验证,编辑等相同的密钥。
为了更加安全,您可以使用私钥,公钥(非对称方式)。 用于创建令牌的专用密钥,用于在客户端级别进行验证的公用密钥。
使用密钥该给什么 您可以输入任何长度的“ sudsif”,“ sdfn2173”
您可以使用在线生成器,也可以手动编写
我更喜欢使用openssl
C:\Users\xyz\Desktop>openssl rand -base64 12
65JymYzDDqqLW8Eg
生成,然后以64为底进行编码
C:\Users\xyz\Desktop>openssl rand -out openssl-secret.txt -hex 20
生成的值保存在名为“ openssl-secret.txt”的文件中
生成并存储到文件中。
一件事情是给12将只生成12个字符,但是由于它是以64为基数编码的,因此它将是(4/3 * n)个上限值。
我建议阅读这篇文章
答案 5 :(得分:0)
如果您正在寻找 JWT_AUTH_SECRET_KEY 的密钥,那么您可以使用此处生成的任何密钥:
https://api.wordpress.org/secret-key/1.1/salt/
这通常用于“WP REST API 的 JWT 身份验证” ( https://wordpress.org/plugins/jwt-authentication-for-wp-rest-api/ )
也许你是像我一样来到这里寻找那个的人:D