{"id":13553517,"url":"https://github.com/dwyl/learn-json-web-tokens","last_synced_at":"2025-05-13T16:11:41.578Z","repository":{"id":26562815,"uuid":"30016822","full_name":"dwyl/learn-json-web-tokens","owner":"dwyl","description":":closed_lock_with_key: Learn how to use JSON Web Token (JWT) to secure your next Web App! (Tutorial/Example with Tests!!)","archived":false,"fork":false,"pushed_at":"2025-01-01T14:50:11.000Z","size":247,"stargazers_count":4190,"open_issues_count":22,"forks_count":253,"subscribers_count":192,"default_branch":"main","last_synced_at":"2025-04-23T22:58:58.191Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dwyl.png","metadata":{"files":{"readme":"README-zh_CN.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-01-29T11:18:27.000Z","updated_at":"2025-04-17T01:16:20.000Z","dependencies_parsed_at":"2024-04-16T20:57:50.464Z","dependency_job_id":"c91619bf-39d7-4bfe-8aac-4c65276b9c2f","html_url":"https://github.com/dwyl/learn-json-web-tokens","commit_stats":{"total_commits":121,"total_committers":31,"mean_commits":3.903225806451613,"dds":"0.47107438016528924","last_synced_commit":"8d4caee5232d65d184646d0c285fb9ad3251f6cd"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dwyl%2Flearn-json-web-tokens","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dwyl%2Flearn-json-web-tokens/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dwyl%2Flearn-json-web-tokens/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dwyl%2Flearn-json-web-tokens/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dwyl","download_url":"https://codeload.github.com/dwyl/learn-json-web-tokens/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250528728,"owners_count":21445514,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T12:02:27.074Z","updated_at":"2025-04-23T22:59:09.715Z","avatar_url":"https://github.com/dwyl.png","language":"JavaScript","funding_links":[],"categories":["JavaScript","Tools","Password-less auth"],"sub_categories":["JSON","JWT"],"readme":"![JWT logo wider](https://i.imgur.com/qDOOu4o.jpg)\n\n# 学习如何使用 **JSON Web Tokens** (JWT) 进行**鉴权**\n\n![dilbert fixed the internet](https://i.imgur.com/cNElVof.jpg)\n\n学习怎么使用 JSON Web Token (JWT) 来**加密**你的 Web 应用或者移动应用!\n\n[![Build Status](https://img.shields.io/travis/dwyl/learn-json-web-tokens/master.svg?style=flat-square)](https://travis-ci.org/dwyl/learn-json-web-tokens)\n[![codecov.io](https://img.shields.io/codecov/c/github/dwyl/learn-json-web-tokens/master.svg?style=flat-square)](https://codecov.io/github/dwyl/learn-json-web-tokens?branch=master)\n[![codeclimate-maintainability](https://img.shields.io/codeclimate/maintainability/dwyl/learn-json-web-tokens.svg?style=flat-square)](https://codeclimate.com/github/dwyl/learn-json-web-tokens/maintainability)\n[![Dependencies Status](https://david-dm.org/dwyl/learn-json-web-tokens/status.svg?style=flat-square)](https://david-dm.org/dwyl/learn-json-web-tokens)\n[![devDependencies Status](https://david-dm.org/dwyl/learn-json-web-tokens/dev-status.svg?style=flat-square)](https://david-dm.org/dwyl/learn-json-web-tokens?type=dev)\n[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat-square)](https://github.com/dwyl/learn-json-web-tokens/issues)\n[![HitCount](https://hits.dwyl.com/dwyl/learn-json-web-tokens.svg)](https://hits.dwyl.io/dwyl/learn-json-web-tokens)\n\n\n## **为什么**?\n\nJSON Web Tokens (JWTs) 使得在服务之间（**包括在你 app 或者网站的内部和外部**） _**发送只读签名**_ 的 “_**声明**_“ 变得很**简单**。\n\n声明是你想让某些人**阅读**或**校验**但不能修改的**任意**字节的数据。\n\n\u003e **注意**：**如果听起来很啰嗦，请不要担心，阅读 5 分钟之后一切都会变得清晰起来的！**\n\n## 是什么?\n\n\u003e “***JSON Web Token***（JWT）是一种紧凑的 URL 安全方式，用于表示在双方之间传输的声明。JWT 中的声明被**编码**为使用JSON Web 签名（JWS）进行数字签名的 **JSON 对象**。——IETF\n\n###  **通俗一点**\n\n为了在你的 app（web或者移动端）中辨识或授权用户，在 **header** 或者页面（或者 API）的 **url** 中放置一个**基于标准的 token**，它表明了这个用户已经登录并且被允许获取到他想要的内容。\n\n示例：`https://www.yoursite.com/private-content/?token=eyJ0eXAiOiJKV1Qi.eyJrZXkiOi.eUiabuiKv`\n\n\u003e **注意**：如果这对于你而言还不够“安全”，往下翻到“[***security***](#q-我把-jwt-放在-url-或者-header-是安全的吗)”这一节。\n\n### JWT **看起来**是什么样的？\n\nTokens 是一系列“url 安全”的字符所组成的字符串，它包含了**编码**后的信息。\nTokens 由**三部分**组成（用小数点分割）,为了便于阅读，下面用三行来展示，但是实际使用时是一个单独的字符串。\n\n```\neyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9           // 头部\n.eyJrZXkiOiJ2YWwiLCJpYXQiOjE0MjI2MDU0NDV9      // 载荷\n.eUiabuiKv-8PYk2AkGY4Fb5KMZeorYBLw261JPQD5lM   // 签名\n```\n\n#### 1. 头部\n\nJWT 的第一部分是一个编码的字符串，它表示一个简单的 JavaScript 对象，这个对象描述了 token 所使用的哈希算法。\n\n#### 2. 载荷\n\nJWT 的第二部分是 token 的核心，负载的长度与你在 JWT 中所存储的数据长度有关。\n通常所遵守的准则是：存储尽量少的必要的数据在 JWT 中。\n\n\n#### 3. 签名\n\n第三部分是最后一部分，是根据头部（第一部分）和主体（第二部分）所计算出来的一个签名，会被用于**校验** JWT 是否有效。\n\n### 什么是“声明”？\n\nClaims are the predefined **keys** and their **values**:\n\n声明是预定义的一系列**键**和它们所对应的**值**：\n\n+ **iss**: token 的发行人。\n+ **exp**: 到期时间戳（已过期的令牌会被拒绝）。注意：如规范中所定义，以秒为单位。\n+ **iat**: token 的发行时间。可以用于判断 JWT 的发行时间长。\n+ **nbf**: \"not before\" 是 JWT 被激活的某个未来时间（可以理解为生效时间）。\n+ **jti**: JWT 的第一无二的标识（编号），用于防止 JWT 被重复使用或者重复产生。\n+ **sub**: token 的主题（很少使用）。\n+ **aud**: token 的受众（同样很少使用）。\n\n详情阅读： https://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#RegisteredClaimName\n\n# 示例 [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/dwyl/learn-json-web-tokens/issues)\n\n让我们通过一个简单的示例来继续深入学习 JWT。\n（**全部**源码都在 **/example** 目录下）\n\n\u003e 动手尝试： https://jwt.herokuapp.com/\n\n可以在 Gitpod（需要通过 GitHub 授权登录） 上亲自动手尝试一下这个示例。\n\n[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io#https://github.com/dwyl/learn-json-web-tokens/blob/master/example/lib/helpers.js)\n\n## 服务器\n\n通过使用 **node.js 的 核心模块 http** 服务器，我们在 **/example/server.js** 创建了四个接口：\n\n1. **/home** : 首页（不是必要的，但是我们的 **login** 表单放在这里）。\n2. **/auth** : 对游客进行**授权** （如果授权失败会返回错误并且回到首页的 login 表单）。\n3. **/private** : 我们的受保护的内容 - ***需要登录***（有合法的会话 token）才能看到这个页面。\n4. **/logout** : 使 token 失效并且登出用户（防止重复使用旧的 token）。\n\n我们已经**有意地**把 **server.js** 写得足够的简单了：\n\n+ 可阅读\n+ 可维护\n+ 可测试（所有的 helper/handler 方法都已经被单独测试）\n\n\u003e 注意： 如果你可以让示例更**简单**，请提交 [issue](https://github.com/dwyl/learn-json-web-tokens/issues) 一起讨论！\n\n## Helper 方法\n\n所有 helper 类方法都保存在 **/example/lib/helpers.js**\n两个最有意思或者说最相关的方法是（下面是简化版本）：\n\n```javascript\n// 构造 JWT 的方法。\nfunction generateToken(req){\n  return jwt.sign({\n    auth:  'magic',\n    agent: req.headers['user-agent'],\n    exp:   Math.floor(new Date().getTime()/1000) + 7*24*60*60; // 注意：单位是秒！\n  }, secret);  // secret 被定义在环境变量 JWT_SECRET 中\n}\n```\n\n当用户进行授权的时候，这个方法会计算出我们的 JWT token，这个 token 随后会被放在 **Authorization** 响应头发送回客户端，用于后续的请求。\n\n另外一个\n\n```javascript\n// 校验请求头 Authorization 中的 token 是否有效。\nfunction validate(req, res) {\n  var token = req.headers.authorization;\n  try {\n    var decoded = jwt.verify(token, secret);\n  } catch (e) {\n    return authFail(res);\n  }\n  if(!decoded || decoded.auth !== 'magic') {\n    return authFail(res);\n  } else {\n    return privado(res, token);\n  }\n}\n```\n\nWhich **checks the JWT supplied by the client is valid**,\nshows private (\"privado\") content to the requestor if valid\nand renders the **authFail** ***error*** page if its not.\n\n该方法**会检查客户端提供的 JWT 是否有效**，如果有效就会展示私有内容（通过 \"privado\" 方法）给请求者；如果校验失败，会通过**authFail** 方法渲染 ***错误页*** 。\n\n**注意**: 这两个方法**都是同步的**。这两个方法都没有进行任何的 IO 操作或者网络请求，所以同步计算是安全的。\n\n\u003e 提示：如果你正在为你的 Hapi.js 应用寻找 ***全能的*** **JWT Auth Hapi.js 插件** （**异步**校验或验证） 请查看： [https://github.com/**dwyl/hapi-auth-jwt2**](https://github.com/dwyl/hapi-auth-jwt2)\n\n## 测试\n\n你可能已经注意到了教程开头的 [![Build Status][travis-image]][travis-url] 这些铭牌，这是一个标志，作者不只是**堆砌**代码在一起。\n\n对服务器路由和 helper 类方法的测试都放在 **/example/test**。\n\n1. /example/test/**functional.js** - 测试我们在 /example/lib/**helpers.js** 中创建的所有 **helper 类方法**。\n[![Test Coverage](https://codeclimate.com/github/dwyl/learn-json-web-tokens/badges/coverage.svg)](https://codeclimate.com/github/dwyl/learn-json-web-tokens)\n2. /example/test/**integration.js** - 模拟**用户**对服务器所发起的请求并测试服务器**响应**。\n\n请**阅读**所有测试案例，如有不清楚的地方，可以**告诉我们**。\n\n**注意**：我们为 http req/res 对象写了一个基本的“**mock**”: /example/test/**mock.js**\n\n如果还不懂 mock 或者很好奇，请阅读：[When to Mock (by \"Uncle Bob\")](https://blog.8thlight.com/uncle-bob/2014/05/10/WhenToMock.html)\n\n- - -\n\n## 常见问题及解答\n\n\u003e ***有问题吗? 马上提问!*** \u003e\u003e https://github.com/dwyl/learn-json-web-tokens/issues\n\n### Q: 我把 JWT 放在 *URL* 或者 *Header* 是**安全**的吗？\n\n问得好！答案是：“**否**”，除非你使用 SSL/TLS 加密你的连接（https），使用[明文](https://en.wikipedia.org/wiki/Plaintext)发送 Token 永远都是不安全的（token 可以被拦截并且被坏蛋重用）。一种比较笨拙简单的方法是添加校验声明到 token，比如检查请求是否来自于同一个浏览器（user-agent），添加IP 地址或者更先进的“[**browser fingerprints**](https://stackoverflow.com/a/3287761/1148249)”…… https://programmers.stackexchange.com/a/122385\n\n解决方案包括:\n+ 使用一次性 token，在链接点击后即失效 ***或者***\n+ 在安全性要求较高的场景下不把 token 放在 url 中。\n(比如：不把执行交易的链接发送给别人)\n\nJWT 放在 url 中的**使用场景**:\n+ 账户校验 - 当你把激活账户的链接通过 Email 发送给在你网站注册了的客户的时候。 `https://yoursite.co/account/verify?token=jwt.goes.here`\n+ 密码重置 - 确保重置密码的人能够登录与账户有关的邮件。\n `https://yoursite.co/account/reset-password?token=jwt.goes.here`\n\n上面的案例都是使用一次性 token 的适用场景 (****点击后就失效****)。\n\n### Q: 怎么使会话失效?\n\n如果使用你 app 的人的**设备**（手机/平板电脑/笔记本电脑）**被盗了**，那你应该如何使它们使用的 token 失效？\n\nJWT 背后的思想是**无状态**，它们可以被集群中的任意节点计算出来并且验证，而不用对数据库发起任何请求。\n\n#### 把 token 存在数据库中?\n\n##### LevelDB\n\n如果你的应用规模比较**小**，或者你不想运行一个 Redis 服务器，你可以通过使用 LevelDB：http://leveldb.org/ 来从 Redis 获取最大的好处。\n\n我们可以把有效的 token 存储在数据库中，或者相反地把非法的 token 存储在数据库中。这两种方案都需要往返数据库以检查 token 是否有效。所以我们倾向于存储所有的 token 到数据库，并且把 token 的 *valid* 字段从 true 更新为 false，表示 token 已经过期。\n\n存储在 LevelDB 中的示例：\n```json\n\"GUID\" : {\n  \"auth\" : \"true\",\n  \"created\" : \"timestamp\",\n  \"uid\" : \"1234\"\n}\n```\n我们将通过 GUID 来查找这条记录：\n\n```js\nvar db = require('level');\ndb.get(GUID, function(err, record){\n  // pseudo-code\n  if(record.auth){\n    // 展示私有内容（通过了校验）\n  } else {\n    // 展示错误信息（校验未通过）\n  }\n});\n```\n通过查看 example/lib/helpers.js 中的 **validate** 方法获取更多详情。\n\n##### Redis\n\nRedis 是存储令牌的**可扩展**方式。\n\n如果你**从未**接触过 Redis，请阅读:\n+ Intro: https://redis.io/topics/introduction\n+ Redis in 30 mins:\nhttps://openmymind.net/2011/11/8/Redis-Zero-To-Master-In-30-Minutes-Part-1/\n+ What is Redis? https://www.slideshare.net/dvirsky/introduction-to-redis\n\nRedis ***Scales*** (provided you have the RAM):\nhttps://stackoverflow.com/questions/10478794/more-than-4-billion-key-value-pairs-in-redis\n\n\u003e ***从现在开始学习 Redis！*** [https://github.com/dwyl/**learn-redis**](https://github.com/dwyl/learn-redis)\n\n#### Memcache?\n\n***Quick* answer**: *使用 **Redis***:\nhttps://stackoverflow.com/questions/10558465/memcache-vs-redis\n\n\n### Q: 返回游客（**会话之间没有状态保存**）\n\nCookie 存储在客户端，并且每次请求时都会由浏览器发送到服务器。如果关闭了浏览器，则会保留 Cookie，因此可以在上次停止的地方继续操作而不必再次登录。但是 cookie 会在与路径和发布域匹配的所有请求上发送，包括不需要的图像和 css 请求。\n\n[`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window.localStorage) 提供了一种更好的在浏览器会话之间存储 token 的机制。\n\n#### 基于浏览器的应用\n\n有以下两种方式存储你的 JWT：\n\n1. 使用 ***localStorage*** 在客户端存储你的 JWT（**意味着你需要把 JWT 放在 `authorization` header 中返回给客户端，以便后续 http/ajax 请求使用**）\n2. 把 JWT 存储在 cookie 中。\n\n\u003e 我们更倾向于第一种方法。但是如果使用得当的话，cookie 仍然可以在现代 web 应用中发挥他们的作用！\n\n##### 一些有用的网站\n\n+ Good ***history*** \u0026 overview of **Localstorage**:\nhttp://diveintohtml5.info/storage.html\n+ MDN **Window.localStorage**:\nhttps://developer.mozilla.org/en-US/docs/Web/API/Window.localStorage\n+ Brief description + basic *examples*:\nhttps://www.html5rocks.com/en/features/storage\n+ Will it work for *my* visitors?\nhttps://caniuse.com/#search=localstorage\n(**Quick answer**: ***Yes***! IE 8 \u0026 above, Android 4.0+, IOS 7.1+, Chrome \u0026 Firefox )\n\n\n#### 编程式（API）访问\n\n其它服务访问你的 API 时必须把令牌存储在检索系统中（比如：移动应用的 Redis 或 SQLite）并且把 token 带入到每一个请求中。\n\n### 如何生成密钥？\n\n\u003e “**如果这个问题在其它地方被提到过的话我感到抱歉。用于计算 token 的私钥和 ssh-keygen 生成的私钥是一样的吗？** ~最初由 [@skota](https://github.com/skota) 提出问题，更多详细: [dwyl/**hapi-auth-jwt2/issues**/48](https://github.com/dwyl/hapi-auth-jwt2/issues/48)\n\n因为 JSON Web Token（JWT）不要求使用[**非对称加密**](https://en.wikipedia.org/wiki/Public-key_cryptography)进行签名，所以**不必**使用 ssh-keygen 生成密钥。你可以简单地只使用一个**强密码**,例如：https://www.grc.com/passwords.htm 提供了足够长的复杂的随机的字符串。这样的话使用相同加密字符串的可能性（有人能够修改有效负载，添加或修改声明以及创建有效签名的可能性）非常低。如果你将两个**强密码**（字符串）连接在一起，你将拥有一个 128 位的 ASCII 字符串。因此，碰撞的可能性小于[宇宙中的原子数](https://en.wikipedia.org/wiki/Observable_universe#Matter_content_.E2.80.94_number_of_atoms)。\n\nTo quickly and easily create a secret key using Node's crypto library, run this command.\n\n使用以下命令可以通过 Node 的 crypto 模块快速而简单地创建一个密钥。\n\n    node -e \"console.log(require('crypto').randomBytes(32).toString('hex'));\"\n\n换句话说，你**可以**使用一个 ***RSA 密钥***，但是这不是必要的。\n\n你需要记住的最重要的一件事就是：不要把这个密钥泄露给核心组（”*DevOps Team*“）成员之外的任何人或者**意外地**将它发布到了 GitHub！\n\n\n## 哪个 Node.js 模块？\n\n在 NPM 上搜索 ”**JSON Web Token**“：https://www.npmjs.com/search?q=json+web+token 会产生许多结果！\n\n![npm search for json web token](https://i.imgur.com/ZLN3LlW.png)\n\n### 使用 Hapi.js 构建 Web 应用？\n\n我们努力简化在 Hapi.js 应用程序中使用 JWT 的过程，在这个过程中我们写了这个模块：https://github.com/dwyl/hapi-auth-jwt2\n\n\n### **其它** Node.js 项目的常用方法\n\n我们**强烈**推荐 **jsonwebtoken** 这个模块，它由我们的朋友[@auth0](https://twitter.com/auth0)\n([校验/鉴权领域的专家](https://auth0.com/about))编写:\n- https://github.com/auth0/node-jsonwebtoken\nWhich in turn uses:\nhttps://github.com/brianloveswords/node-jws\n[![NPM][jsonwebtoken-icon] ][jsonwebtoken-url]\n\n另外一个非常棒的选择是： https://github.com/joaquimserafim/json-web-token\n也是我们的朋友 [@joaquimserafim](https://github.com/joaquimserafim) 编写的。\n\n## 必要的阅读(**预习**)\n\n- Original **Specification** (Draft):\nhttps://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32\n- Great overview from Atlassian:\nhttps://developer.atlassian.com/cloud/jira/platform/understanding-jwt/\n- Good intro (ruby-specific examples):\nhttps://www.intridea.com/blog/2013/11/7/json-web-token-the-useful-little-standard-you-haven-t-heard-about\n+ Friendlier introduction: https://jwt.io/\n+ Getting to know JWT:\nhttps://scotch.io/tutorials/the-anatomy-of-a-json-web-token\n- Discussion: https://ask.auth0.com/c/jwt\n+ ***How to*** do **stateless authentication** (session-less \u0026 cookie-less):\nhttps://stackoverflow.com/questions/20588467/how-to-do-stateless-session-less-cookie-less-authentication\n\n\n## 深入阅读(**推荐**) [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/dwyl/learn-json-web-tokens/issues)\n\n+ JWT with Passport.js:\nhttps://stackoverflow.com/questions/20228572/passport-local-with-node-jwt-simple\n+ JWT Tokens as API Keys:\nhttps://auth0.com/blog/2014/12/02/using-json-web-tokens-as-api-keys/\n+ **10 Things you should know** about ***Tokens and Cookies***:\nhttps://auth0.com/blog/2014/01/27/ten-things-you-should-know-about-tokens-and-cookies/#xss-xsrf\n+ Information Security discussion:\nhttps://security.stackexchange.com/questions/51294/json-web-tokens-jwt-as-user-identification-and-authentication-tokens\n+ Using JWT with node.js (express + backbone):\nhttps://www.sitepoint.com/using-json-web-tokens-node-js/\n+ Token-based Authentication with Socket.IO\nhttps://auth0.com/blog/2014/01/15/auth-with-socket-io/\n+ JWT Auth *discussion* on Hacker News:\nhttps://news.ycombinator.com/item?id=7084435\n+ The Spec but nicer:\nhttps://self-issued.info/docs/draft-ietf-oauth-json-web-token.html\n+ Extended (Wiki) article on Claims-based authentication:\nhttps://en.wikipedia.org/wiki/Claims-based_identity\n+ Securing Requests with JWT:\nhttps://websec.io/2014/08/04/Securing-Requests-with-JWT.html\n+ Avoid Database in authenticating user for each request (stateless):\nhttps://security.stackexchange.com/questions/49145/avoid-hitting-db-to-authenticate-a-user-on-every-request-in-stateless-web-app-ar\n+ The Twelve-Factor App: https://12factor.net/ + https://12factor.net/processes\n+ Auth in Hapi with JWT: https://medium.com/@thedon/auth-in-hapi-with-jwt-780ce4d072c7#.clgj5lknq\n+ Token based authentication in Node.js with Passport, JWT and bcrypt: https://jonathas.com/token-based-authentication-in-nodejs-with-passport-jwt-and-bcrypt/\n\n# **感谢**您和我们一起学习！\n\n如果您认为这篇快速阅读很有帮助, 请在 GitHub 上给我们一颗星星（Star）并且转推分享给其他人：https://twitter.com/olizilla/status/626487231860080640\n\n[![olizilla tweet](https://i.imgur.com/rCvNvvk.jpg)](https://twitter.com/olizilla/status/626487231860080640 \"Please Re-Tweet!\")\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdwyl%2Flearn-json-web-tokens","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdwyl%2Flearn-json-web-tokens","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdwyl%2Flearn-json-web-tokens/lists"}