jwt如何验证验证码_如何使用节点创建和验证JWT

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/createhttp://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.jsres.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()函数,令牌将在一分钟后过期,这将使您看到过期时会发生什么,而不必等待太久。

免费学习PHP!

全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。

原价$ 11.95 您的完全免费

要进行测试并获得令牌,请通过/create端点登录。 同样,您可以转到浏览器, http://localhost:3000/createhttp://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 ,然后点击保存

okta应用设置

创建应用程序后进入的页面包含需要保存到.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 authindex.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,因此您可能需要使用其他浏览器或隐身窗口来查看登录屏幕,就像您网站的其他访问者一样。

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如何验证验证码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值