JS总结笔记:基于 Token 的身份验证:JSON Web Token

Token

什么是Token?

在计算机身份认证中是令牌(临时)的意思,在词法分析中是标记的意思。一般我们所说的的token大多是指用于身份验证的token

为什么使用token?

我们需要每次都知道当前请求的人是谁,但是又不想每次都让他提交用户名和密码,这时就需要有一个等同于用户名密码也能够标识用户身份的东西,即—token

基于Token的身份验证方法(步骤)

  1. 客户端使用用户名和密码请求登录
  2. 服务端收到请求,验证登录是否成功
  3. 验证成功后,服务端会返回一个Token给客户端,反之,返回身份验证失败的信息
  4. 客户端收到Token后把Token用一种方式存储起来,如( cookie / localstorage / sessionstorage / 其他 )
  5. 客户端每次发起请求时都会将Token发给服务端
  6. 服务端收到请求后,验证Token的合法性,合法就返回客户端所需数据,反之,返回验证失败的信息

JWT(Json Web Tokens)

生成Token的解决方案有许多,常用的一种就是 Json Web Tokens

JWT标准的Tokens由三部分组成:

  1. header:包含token的类型和加密算法
  2. payload:包含token的内容
  3. signature:通过密钥将前两者加密得到最终的token

这三部分中间使用 " . " 分隔开,并且都会使用Base64编码方式编码,如下

eyJhbGc6IkpXVCJ9.eyJpc3MiOiJCIsImVzg5NTU0NDUiLCJuYW1lnVlfQ.SwyHTf8AqKYMAJc

header

header 部分主要是两部分内容,一个是 Token 的类型,另一个是使用的算法,比如下面类型就是 JWT,使用的算法是 Hash256
头部里包含的东西可能会根据 JWT 的类型有所变化,比如一个加密的 JWT 里面要包含使用的加密的算法。唯一在头部里面要包含的是 alg 这个属性,如果是加密的 JWT,这个属性的值就是使用的签名或者解密用的算法。如果是未加密的 JWT,这个属性的值要设置成 none

{
  "typ": "JWT",
  "alg": "HS256"
}

payload

Payload 里面是 Token 的具体内容,这些内容里面有一些是标准字段,你也可以添加其它需要的内容。下面是标准字段:

  • iss:Issuer,发行者
  • sub:Subject,主题
  • aud:Audience,观众
  • exp:Expiration time,过期时间
  • nbf:Not before
  • iat:Issued at,发行时间
  • jti:JWT ID

比如下面这个 Payload ,用到了 iss 发行人,还有 exp 过期时间这两个标准字段。另外还有两个自定义的字段,一个是 name ,还有一个是 admin

{
 "iss": "ninghao.net",
 "exp": "1438955445",
 "name": "wanghao",
 "admin": true
}

signature

JWT 的最后一部分是 Signature ,这部分内容有三个部分,先是用 Base64 编码的 header.payload ,再用加密算法加密一下,加密的时候要放进去一个 Secret ,这个相当于是一个密码,这个密码秘密地存储在服务端

  • header
  • payload
  • secret
const encodedString = base64UrlEncode(header) + "." + base64UrlEncode(payload); 
HMACSHA256(encodedString, 'secret');

处理完成以后看起来像这样:

SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc

最后这个在服务端生成并且要发送给客户端的 Token 看起来像这样:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.		//header
eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ.		//payload
SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc		//signature

客户端收到这个 Token 以后把它存储下来,下回向服务端发送请求的时候就带着这个 Token
服务端收到这个 Token ,然后进行验证,通过以后就会返回给客户端想要的资源

签发与验证 JWT

在应用里实施使用基于 JWT 这种 Token 的身份验证方法,你可以先去找一个签发与验证 JWT 的功能包。无论你的后端应用使用的是什么样的程序语言,系统,或者框架,你应该都可以找到提供类似功能的包

实例演示
使用node.js实现jwt验证

准备项目

准备一个简单的 Node.js 项目
安装签发与验证 JWT 的功能包,我用的叫 jsonwebtoken,在项目里安装一下这个包

cnpm install jsonwebtoken -S
在这里插入图片描述

签发 JWT

在项目里随便添加一个 .js 文件,比如 index.js,在文件里添加下面这些代码

const jwt = require('jsonwebtoken')//const定义的变量不可以修改,而且必须初始化

// Token 数据
const payload = {
  name: 'guoxiansheng',
  admin: true
}

// 密钥
const secret = 'STUDYJWT' // 这是加密的key(密钥或私钥) 

// 签发 Token
const token = jwt.sign(payload, secret, { expiresIn:60*60*24})//expiresIn设置为24小时过期

// 输出签发的 Token
console.log(token)

非常简单,就是用了刚刚为项目安装的 jsonwebtoken 里面提供的 jwt.sign 功能,去签发一个 token。这个 sign 方法需要三个参数:

  1. playload:签发的 token 里面要包含的一些数据
  2. secret:签发 token 用的密钥,在验证 token 的时候同样需要用到这个密钥
  3. options:一些其它的选项

在命令行下面,用 node 命令,执行一下项目里的 index.js 这个文件(node index.js),会输出应用签发的 token:

C:\Users\Administrator\Desktop\work\JWT>node index.js	//执行的命令
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiZ3VveGlhbnNoZW5nIiwiYWRtaW4iOnRydWUsImlhdCI6MTU1MDQ4NDMzOSwiZXhwIjoxNTUwNTcwNzM5fQ.UqlYyQK4wzw5DtHlr2TupI4Ja2fU6tIF5DhASDLoBwM

上面的 Token 内容并没有加密,所以如果用一些 JWT 解码功能,可以看到 Token 里面包含的内容,内容由三个部分组成,像这样:

// header
{
  "alg": "HS256", //对称算法HS256 签名和验证的时候都会用同一个密码
  "typ": "JWT"
}

// payload
{
  name: 'guoxiansheng',
  admin: true,
  iat: 1550484653,	//生成Token的时间
  exp: 1550571053 	//Token的过期时间
}

// signature
UqlYyQK4wzw5DtHlr2TupI4Ja2fU6tIF5DhASDLoBwM

假设用户通过了某种身份验证,你就可以使用上面的签发 Token 的功能为用户签发一个 Token。一般在客户端那里会把它保存在 Cookie 或 LocalStorage 里面

用户下次向我们的应用请求受保护的资源的时候,可以在请求里带着我们给它签发的这个 Token,后端应用收到请求,检查签名,如果验证通过确定这个 Token 是我们自己签发的,那就可以为用户响应回他需要的资源

验证 JWT
验证 JWT 的用效性,确定一下用户的 JWT 是我们自己签发的,首先要得到用户的这个 JWT Token,然后用 jwt.verify 这个方法去做一下验证。这个方法是 Node.js 的 jsonwebtoken 这个包里提供的,在其它的应用框架或者系统里,你可能会找到类似的方法来验证 JWT。

打开项目的 index.js 文件,里面添加几行代码:

// 验证 Token

jwt.verify(token, 'bad secret', (error, decoded) => {
  if (error) {
    console.log(error.message)
    return
  }
  console.log(decoded)
})

把要验证的 Token 数据,还有签发这个 Token 的时候用的那个密钥告诉 verify 这个方法,在一个回调里面有两个参数,error 表示错误,decoded 是解码之后的 Token 数据。

执行:

C:\Users\Administrator\Desktop\work\JWT>node index.js

输出:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiZ3VveGlhbnNoZW5nIiwiYWRtaW4iOnRydWUsImlhdCI6MTU1MDQ5MDIyNywiZXhwIjoxNTUwNTc2NjI3fQ.1WMLfVytNgCXyjtok7oE4JincarM4vWXXtfxNtpPwK8
invalid signature

注意输出了一个 invalid signature ,表示 Token 里的签名不对,这是因为我们组长 verify 方法提供的密钥并不是签发 Token 的时候用的那个密钥。这样修改一下:

jwt.verify(token, secret, (error, decoded) => { ...

再次运行,会输出类似的数据:

C:\Users\Administrator\Desktop\work\JWT>node index.js
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiZ3VveGlhbnNoZW5nIiwiYWRtaW4iOnRydWUsImlhdCI6MTU1MDQ5MDIxNCwiZXhwIjoxNTUwNTc2NjE0fQ.AxoDKLOFBpjmhRDHq5xkhqm8UNSOnTfW3oQOetfo10w
{ name: 'guoxiansheng',
  admin: true,
  iat: 1550490214,
  exp: 1550576614 }

当然还可以采用RS256 算法签发验证Token
非对称算法RS256
签名和验证的时候用的不是同一个密码

注意事项

设置token过期时间
如果你使用expiresInMinutes来设置token的过期时间,很抱歉它会抛出如下异常

ValidationError: "expiresInMinutes" is not allowed

请使用expiresIn:以秒为单位或描述的时间跨度字符串表示rauchg / MS。


如:60,”2 days”,”10h”,”7d”

{expiresIn: 60} // 有效期60秒(没有时间单位以秒为准)
{expiresIn: "2 days"} // 有效期 2天 (后缀为时间单位)下面的类似
...... 
('1d') // 86400000
('10h') // 36000000
('2.5 hrs') // 9000000
('2h') // 7200000
('1m') // 60000
('5s') // 5000
('1y') // 31557600000

verify(验证)时返回的err的值
token过了有效期的时错误信息

"err": {
"name": "TokenExpiredError",
"message": "jwt expired", // token过了有效期
"expiredAt": "2016-11-07T03:31:25.000Z"
}

遇到伪造或无效的token时的错误信息

"err": {
"name": "JsonWebTokenError",
"message": "invalid token" // 伪造/无效的token
}

参考地址
https://ninghao.net/blog/2834
学习视频
https://ninghao.net/course/5018#toc

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在 PHP 中实现 token 登录需要以下步骤: 1. 在用户登录时,服务器端需要验证用户的身份信息(例如用户名和密码)。 2. 如果用户身份验证通过,服务器端将生成一个 token。这个 token 会包含一些用户的信息(例如用户 ID),并使用密钥进行加密。 3. 服务器端将这个 token 返回给客户端,客户端将 token 保存在本地(例如浏览器的 cookie 中)。 4. 在客户端发起请求时,会将 token 一并发送给服务器端。服务器端使用密钥解密 token,并校验 token 的合法性。如果 token 合法,则表示用户已登录;如果 token 不合法,则表示用户未登录。 下面是一个简单的 PHP 代码示例,展示了如何生成和校验 token: ``` <?php // 密钥 $secret = 'your-secret-key'; // 用户信息 $user = [ 'id' => 123, 'username' => 'john', ]; // 生成 token $header = [ 'alg' => 'HS256', 'typ' => 'JWT', ]; $payload = [ 'sub' => $user['id'], 'iat' => time(), 'exp' => time() + 3600, // 过期时间为 1 小时 ]; $header = base64_encode(json_encode($header)); $payload = base64_encode(json_encode($payload)); $signature = hash_hmac('sha256', "$header.$payload", $secret, true); $signature = base64_encode($signature); $token ### 回答2: PHP实现Token登录可以通过以下步骤来实现: 1. 首先,生成Token:在用户登录成功后,通过调用一些生成Token的函数来生成一个唯一的字符串。可以使用PHP的内置函数如`md5()`或`uniqid()`来生成Token。 2. 将Token保存到数据库中:将生成的Token与用户信息关联起来,并将其存储到数据库中的用户表中。可以在用户表中新建一个字段来存储Token信息。 3. 将Token返回给客户端:在生成Token并存储到数据库后,将Token返回给客户端。可以通过将Token作为响应的一部分以JSON格式返回给客户端。 4. 客户端存储Token:客户端在收到Token后,可以将其存储到Cookie或者本地存储中。这样可以在之后的请求中将Token作为认证凭证发送给服务器。 5. 验证Token:在每次请求中,服务器需要验证客户端发送过来的Token的有效性。可以通过查询数据库,检查Token是否存在且匹配用户信息。 6. Token过期处理:可以通过设置Token的有效期或者设置定期过期机制来处理过期Token。当Token过期时,需要重新生成Token并更新用户表中的Token字段。 7. 注销Token:在用户注销或者退出登录时,应该将Token从客户端和服务器端同时删除。可以通过清除Cookie或者删除本地存储中的Token来实现。 通过以上步骤,可以使用PHP实现Token登录,提高系统的安全性和用户的使用体验。 ### 回答3: 在PHP中实现token登录是一种常见的身份验证机制。Token是一个包含用户信息和签名的字符串,用于验证用户的身份和权限。 实现token登录主要可以分为以下几个步骤: 1. 用户登录:用户使用用户名和密码进行登录,验证成功后生成一个token,并将token存储到服务器端和返回给客户端。 2. Token生成:在服务器端生成一个token,可以使用一些加密技术如HMAC(基于密钥的消息认证码)算法,将用户的信息和一些固定的或随机的字符串组合起来生成一个唯一的token。 3. Token存储:将token存储到服务器端,可以选择将token存储到数据库、缓存中或者直接存储到服务器的内存中。 4. Token验证:当用户进行后续请求时,将token作为参数或者HTTP头部的一部分发送到服务器,服务器端接收到token后,进行验证。验证可以通过比较接收到的token与存储的token是否一致,以及检查token的有效期等方式来进行。 5. Token刷新:为避免token的滥用,可以设置token的有效期,并在一定时间后要求用户进行重新验证。当token过期时,用户可以使用存储在客户端的refresh token来刷新token,即生成一个新的token。 通过以上步骤,可以实现token登录的功能,并提供一种安全、高效的身份验证方法,避免了传统的基于会话的认证方式中需要保存用户状态的问题。同时,token登录还具有跨平台、跨语言的特性,使得不同系统之间的身份验证更加简便。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值