jwt如何验证验证码
本文最初发布在Okta开发人员博客上 。 感谢您支持使SitePoint成为可能的合作伙伴。
多年来,互联网上的身份验证已经发展了很多。 有很多方法可以做到这一点,但是在90年代行之有效的方法今天还不能完全解决。 在本教程中,我将简要介绍一些较旧的,更简单的身份验证形式,然后向您展示一种更现代,更安全的方法。 在本文结束时,您将能够在Node中自己创建和验证JWT。 我还将向您展示如何利用Okta在幕后为您完成所有操作。
传统上,执行授权的最简单方法是使用用户名和密码。 这称为“基本授权”,只需将username:password
作为编码字符串发送即可,任何人都可以解码。 您可以将该字符串视为“令牌”。 问题是,您在每次请求时都发送密码。 您也可以一次发送用户名和密码,然后让服务器为您创建一个会话ID。 然后,客户端会将该ID与每个请求一起发送,而不是发送用户名和密码。 这种方法同样有效,但是对于客户端来说,存储和维护会话可能会很麻烦,尤其是对于大量用户而言。
管理授权的第三种方法是通过JSON Web令牌或JWT。 在过去的几年中,JWT已成为事实上的标准。 JWT提出了一组可以验证的主张(例如,“我是芝加哥的香肠之王阿贝·弗洛曼”)。 像基本授权一样,任何人都可以阅读声明。 但是,与Basic Auth不同,您不会与任何在听的人共享密码。相反,这全都是关于信任的。
信任,但要验证……您的JWT
好吧,也许不相信您在互联网上阅读的所有内容。 您可能想知道有人如何提出要求并期望服务器相信这些要求。 当您使用JWT提出索赔时,该索赔将由具有密钥的服务器签名。 即使不知道所使用的机密,读取密钥的服务器也可以轻松地验证该声明是否有效。 但是,如果没有访问该秘密密钥的权限,几乎没有人可以修改声明并确保签名有效。
为什么要使用JWT?
使用JWT可使服务器将身份验证转移到他们信任的第三方。 只要您信任第三方,就可以让他们确保用户就是他们所说的。 然后,第3方将创建一个JWT,以传递任何必要的信息到您的服务器。 通常,这至少包括用户的用户ID(标准称为“主题”的sub
),令牌的“发行者”( iss
)和“到期时间”( exp
)。 有很多标准化的声明,但是您确实可以在声明中放入所需的任何JSON。 只要记住您包含的信息越多,令牌就会越长。
构建一个简单的节点应用
要创建和验证自己的JWTs,您首先需要建立一个节点服务器(当然,你不必 ,但是这就是我今天可以教你)。 首先,运行以下命令来设置新项目:
mkdir fun-with-jwts
cd fun-with-jwts
npm init -y
npm install express@4.16.4
npm install -D nodemon@1.18.6
接下来,创建一个新文件index.js
,其中将包含一个超级简单的节点服务器。 这里有三个端点,只是将TODO
存根作为实现的注释。
/create
端点将需要基本授权才能登录。如果您正在编写真实的OAuth服务器,则可能会使用基本身份验证以外的其他功能。 您还需要在数据库中查找用户,并确保他们提供了正确的密码。 为了使演示更简单,我在此处仅硬编码了一个用户名和密码,因此我们可以专注于JWT功能。
/verify
端点将JWT作为要解码的参数。
const express = require('express')
const app = express()
const port = process.env.PORT || 3000
app.get('/create', (req, res) => {
if (req.headers.authorization !== 'Basic QXp1cmVEaWFtb25kOmh1bnRlcjI=') {
res.set('WWW-Authenticate', 'Basic realm="401"')
res.status(401).send('Try user: AzureDiamond, password: hunter2')
return
}
res.send('TODO: create a JWT')
})
app.get('/verify/:token', (req, res) => {
res.send(`TODO: verify this JWT: ${req.params.token}`)
})
app.get('/', (req, res) => res.send('TODO: use Okta for auth'))
app.listen(port, () => console.log(`JWT server listening on port ${port}!`))
现在,您可以通过键入node_modules/.bin/nodemon .
来运行服务器node_modules/.bin/nodemon .
。 这将在端口3000上启动服务器,并在您对源代码进行更改时自动重新启动。 您可以通过在浏览器中访问http://localhost:3000
来访问它。 要访问不同的端点,您需要将URL更改为http://localhost:3000/create
或http://localhost:3000/verify/asdf
。 如果您更喜欢在命令行中工作,则可以使用curl
击中所有这些端点:
$ curl localhost:3000
TODO: use Okta for auth
$ curl localhost:3000/create
Try user: AzureDiamond, password: hunter2
$ curl AzureDiamond:hunter2@localhost:3000/create
TODO: create a JWT
$ curl localhost:3000/verify/asdf
TODO: verify this JWT: asdf
在您的Node App中创建JSON Web令牌
JSON Web令牌包含三个部分。 标头 , 有效负载和签名 ,以分隔.
s。
标头是base64编码的JSON对象,用于指定要使用的算法和令牌的类型。
有效负载也是base64编码的JSON对象,其中包含您想要的任何内容。 通常,它将至少包含到期时间戳记和一些标识信息。
签名使用标头中指定的算法对标头,有效负载和秘密密钥进行哈希处理。
有许多工具可以为各种语言创建JWT。 对于Node,一个简单的就是njwt
。 要将其添加到您的项目中,请运行
npm install njwt@0.4.0
现在,将index.js
的res.send('TODO: create a JWT')
行替换为以下内容:
const jwt = require('njwt')
const claims = { iss: 'fun-with-jwts', sub: 'AzureDiamond' }
const token = jwt.create(claims, 'top-secret-phrase')
token.setExpiration(new Date().getTime() + 60*1000)
res.send(token.compact())
随意弄乱有效载荷。 使用上面的setExpiration()
函数,令牌将在一分钟后过期,这将使您看到过期时会发生什么,而不必等待太久。
![](https://i-blog.csdnimg.cn/blog_migrate/632a3f0808afea91d61820af2199e9e9.png)
免费学习PHP!
全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。
原价$ 11.95 您的完全免费
要进行测试并获得令牌,请通过/create
端点登录。 同样,您可以转到浏览器, http://localhost:3000/create
为http://localhost:3000/create
,或使用curl:
$ curl AzureDiamond:hunter2@localhost:3000/create
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJoZWxsbyI6IndvcmxkISIsIm51bWJlciI6MC41MzgyNzE0MTk3Nzg5NDc4LCJpYXQiOjE1NDIxMDQ0NDgsImV4cCI6MTU0MjEwNDUwOCwiaXNzIjoiZnVuLXdpdGgtand0cyIsInN1YiI6IkF6dXJlRGlhbW9uZCJ9.LRVmeIzAYk5WbDoKfSTYwPx5iW0omuB76Qud-xR8We4
在您的Node App中验证JSON Web令牌
好吧,这看起来有点像胡言乱语。 您可以看到有两个.
在JWT中,将标头,有效载荷和签名分隔开,但是它不是人类可读的。 下一步是编写一些东西以将该字符串解码为更清晰的东西。
替换包含TODO: verify this JWT
的行TODO: verify this JWT
使用以下命令TODO: verify this JWT
:
const jwt = require('njwt')
const { token } = req.params
jwt.verify(token, 'top-secret-phrase', (err, verifiedJwt) => {
if(err){
res.send(err.message)
}else{
res.send(verifiedJwt)
}
})
在/verify/:token
路由中, :token
部分告诉express,您希望将URL的该部分作为参数读取,因此可以在req.params.token
上获取它。 然后,您可以使用njwt
尝试验证令牌。 如果失败,则可能意味着很多事情,例如令牌格式错误或已过期。
返回您的网站,或者在curl中,使用http://localhost:3000/create
创建另一个令牌。 然后将其复制并粘贴到URL中,以便您拥有http://localhost:3000/verify/eyJhb...R8We4
。 您应该得到如下内容:
{
"header": { "typ": "JWT", "alg": "HS256" },
"body": {
"iss": "fun-with-jwts",
"sub": "AzureDiamond",
"jti": "3668a38b-d25d-47ee-8da2-19a36d51e3da",
"iat": 1542146783,
"exp": 1542146843
}
}
如果您稍等片刻然后重试,您将得到jwt expired
。
将OIDC中间件添加到您的Node App中以处理JWT功能
好吧,还算不错。 但是我确实掩盖了很多细节。 这个top-secret-phrase
并不是真正的绝密。 您如何确定自己有一个安全且不容易找到的人? 所有其他JWT选项呢? 您实际上如何将其存储在浏览器中? 令牌的最佳到期时间是多少?
Okta就是在这里玩的。 您可以利用Okta的云服务为您处理所有事情,而不是自己处理所有这些事情。 经过几分钟的设置,您可以停止思考如何确保您的应用程序安全,而仅关注使其独特之处。
为什么要使用Okta进行身份验证?
Okta是一项云服务,允许开发人员创建,编辑和安全地存储用户帐户和用户帐户数据,并将它们与一个或多个应用程序连接。 我们的API使您能够:
如果您还没有一个,请注册一个永久性的开发者帐户 。
创建一个Okta服务器
您将需要保存一些信息以在您的应用中使用。 创建一个名为.env
的新文件。 在其中输入您的Okta组织网址。
HOST_URL=http://localhost:3000
OKTA_ORG_URL=https://{yourOktaOrgUrl}
您还需要一个随机字符串作为会话的“应用程序秘密”。 您可以使用以下命令生成它:
npm install -g uuid-cli
echo "APP_SECRET=`uuid`" >> .env
接下来,登录到开发人员控制台,导航至“ 应用程序” ,然后单击“ 添加应用程序” 。 选择“ Web” ,然后单击“ 下一步” 。 为您的应用程序命名,例如“与JWT一起玩”。 将基本URI更改为http://localhost:3000/
,将登录重定向URI更改为http://localhost:3000/implicit/callback
,然后单击完成。
点击编辑并添加http://localhost:3000/
的注销重定向URL ,然后点击保存 。
创建应用程序后进入的页面包含需要保存到.env
文件的更多信息。 复制客户ID和客户机密。
OKTA_CLIENT_ID={yourClientId}
OKTA_CLIENT_SECRET={yourClientSecret}
现在回到代码。 您需要添加Okta的OIDC中间件来控制身份验证。 它还依赖于使用会话。 您将需要使用dotenv
从.env
文件中读取变量。 要安装所需的依赖项,请运行以下命令:
npm install @okta/oidc-middleware@1.0.2 dotenv@6.1.0 express-session@1.15.6
在index.js
文件的最顶部,您需要包括dotenv
。 这样可以使您的程序可以读取.env
文件中的机密。 在其他任何内容之前添加此行:
require('dotenv').config()
为了安全地设置Okta,您需要告诉Express使用Okta的OIDC中间件,该中间件也需要会话。 查找包含TODO: use Okta for auth
的行TODO: use Okta for auth
在index.js
文件中TODO: use Okta for auth
,然后在其上方输入以下内容以使用所有环境变量初始化Okta:
const session = require('express-session')
const { ExpressOIDC } = require('@okta/oidc-middleware')
app.use(session({
secret: process.env.APP_SECRET,
resave: true,
saveUninitialized: false
}))
const oidc = new ExpressOIDC({
issuer: `${process.env.OKTA_ORG_URL}/oauth2/default`,
client_id: process.env.OKTA_CLIENT_ID,
client_secret: process.env.OKTA_CLIENT_SECRET,
redirect_uri: `${process.env.HOST_URL}/authorization-code/callback`,
scope: 'openid profile'
})
app.use(oidc.router)
现在您已经完成所有设置,创建安全路由将变得轻而易举! 要对其进行测试,请替换其余的TODO: use Okta for auth
,并使用如下路由:
app.get('/', oidc.ensureAuthenticated(), (req, res) => res.send('Peekaboo!'))
现在,当您访问http://localhost:3000
,您将被重定向到一个安全的登录页面。 由于您可能仍从管理面板登录到Okta,因此您可能需要使用其他浏览器或隐身窗口来查看登录屏幕,就像您网站的其他访问者一样。
登录后,您将收到隐藏的消息!
了解有关节点,JWT和安全用户管理的更多信息
当然,您可以做的不仅仅是打印Peekaboo!
还可以做更多有意义的事情Peekaboo!
,但这里的主要要点是,在快速设置之后,您可以通过添加简单的oidc.ensureAuthenticated()
将身份验证添加到Express服务器中的任何路由。 Okta负责管理用户,存储会话,创建和验证JWT,因此您不必这样做!
如果您想了解有关JWT或Node的更多信息,请查看Okta开发人员博客上的其他一些文章:
如果您对此帖子有任何疑问,请在下面添加评论。 有关更多精彩内容, 请在Twitter上关注@oktadev , 在Facebook上关注我们,或订阅我们的YouTube频道 。
翻译自: https://www.sitepoint.com/how-to-create-and-verify-jwts-with-node/
jwt如何验证验证码