继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

NodeJS(Express框架)实现 Token 验证免密登录 (一)

不是阿怪的阿怪
关注TA
已关注
手记 1
粉丝 0
获赞 1

看文章之前,强烈建议先把项目拉取下来!案例来自小弟的开源项目「项目Github」

文章内容只是个人学习的一些总结经验,不具有权威性,这是 Node 服务端的实现,后面会写前端的实现

什么是 Token 验证

常见的 Token 验证方式种:

  • OAuth2,例如:微信授权登录 (貌似也属于 Token 验证)
  • 基于 JWT 的 Token 验证,KiteBlog 里面使用的就是这种。

什么是 JWT (JSON WEB TOKEN) ?

NodeJS (Express) 中实现 Token 的生成和验证

安装 jsonwebtoken 和 express-jwt

首先我们先安装 jsonwebtokenexpress-jwt 这两个中间件

jsonwebtoken: 用于生成 Token 。它也有解析 Token 的功能

express-jwt: 用于解析 Token(比 jsonwebtoken 解决方便) , 它把解析之后的数据,存放到 requset.user

# 安装 jsonwebtoken
npm i jsonwebtoken

# 安装 express-jwt
npm i express-jwt

生成 token

如果你看了上面 JWT 介绍的文章,就知道 JWT 是由三部分组成的,分别是载荷(Payload)头部(Header)签名(Signature)

jsonwebtoken 给我们提供了sign(payload, secretOrPrivateKey, [options, callback])方法。sign 方法对应的其实就是 JWT 签名(Signature)的动作

payload:荷载 ,参数类型:对象 secretOrPrivateKey:自定义的密钥,密钥属于敏感信息。参数类型:字符串 options:可以配置 header 、荷载、指定算法类型。参数类型:对象 callback:回调

眼尖的朋友应该发现,payloadoptions 两个参数都可以配置荷,下面有例子。根据自己的习惯选择就好

Payload 部分 JWT 规定了7个官方字段,这些字段都是可选字段。可直接以对象的形式传给 payload 参数。

iss (issuer):签发人
exp (expiration time):过期时间
sub (subject):主题
aud (audience):受众
nbf (Not Before):生效时间
iat (Issued At):签发时间
jti (JWT ID):编号

options 中也可以接受以上七个字段,不过字段名称有所区别。

iss ---- issuer
exp ---- expiresIn
sub ---- subject
aud ---- audience
nbf ---- notBefore
iat ---- noTimestamp
jti ---- jwtid

除此之后 options 提供了algorithmheader,分别对应使用的加密算法和 JWT 的 Header 部分,其实 algorithm 应该也是属于 Header 部分的。

说了这么多,其实我们一般常用的只有 exp(expiresIn)algorithm 这两个字段,

例子一:

token 的有效时间是配置在 option

//先引入 jsonwebtoken
var jsonWebToken = require('jsonwebtoken');

//密钥,当然实际的项目中密钥应该变态一些
const SECRET_KEY = 'kite1874'

const token = jsonWebToken.sign({
	// Payload 部分,官方提供七个字段这边省略,可以携带一些可以识别用户的信息。例如 userId。
	// 千万不要是用敏感信息,例如密码,Payload 是可以解析出来的。
	userId:user.userId
	role:user.role
},SECRET_KEY,{
	expiresIn:"24h", //token有效期
	// expiresIn: 60 * 60 * 24 * 7,  两种写法
	// algorithm:"HS256"  默认使用 "HS256" 算法
})

console.log(token)

例子二:

我们也可以在 payload 里配置有效时间

const token = jsonWebToken.sign({
	//exp 的值是一个时间戳,这里表示 1h 后 token 失效
	exp:Math.floor(Date.now() / 1000) + (60 * 60)
	userId:user.userId
	role:user.role
},SECRET_KEY)

jsonwebtoken 除了生成 token 外,还提供了解析验证 token 的方法,jwt.verify(token, secretOrPublicKey, [options, callback])

验证 token

express-jwt 是针对 express框架开发的 JWT Token 验证中间件。我先来简单说以下它的用法。

主要有两种方式,一种是哪些请求需要验证就往哪里加验证;另外一种是先给全部请求加上验证,再给不需要验证的请求配置白名单

方式一:

var express = require('express');
var jwt = require('express-jwt');
var app = express();

//SECRET_KEY 要与生成 Token 时保持一致 
const SECRET_KEY = 'kite1874' 

// secret 为密钥,algorithms 为算法。需要注意的是,如果你生成 Token 的时候没有手动设置 algorithm 
// 默认是使用 HS256 来加密的。「express-jwt 6.0」版本需要加 algorithms: ['HS256'] , 说起来都是泪!
app.get("/test", 
jwt({ secret: SECRET_KEY, algorithms: ['HS256']}),
function(req,res){
	//do something...
})

看完上面的例子,很显然不符合我们的逾期,一个正常的项目有个几十个 api 是分分钟的事。我们不可能一个个给他加上检验

方式二:

//注册中间件,相当于配置一个全局 token 验证,unless 就是上面说的白名单
//把不需要 token 验证的请求填进 path 里即可, 支持数组、字符串、正则

app.use(jwt({ secret: SECRET_KEY, algorithms: ['HS256']})
.unless({path: ['/auth/adminLogin',/^\/public\/.*/]}));
// /auth/adminLogin api 和 public 下的文件都不需要 token 验证

这种方式是不是方便很多,而且更美观,维护起来也更方便

Token 解析出来的用户信息,默认存放在 req.user, 可以直接 req.user.userId来使用生成 Token 时填进去的用户id

你也通过 requestPropertyresultProperty 来设置用户信息存放的对象。

验证错误处理

可以使用 app.use() 来注册处理验证不通过的情况

app.use(function (err, req, res, next) {
  if (err.name === 'UnauthorizedError') {
    res.status(401).send("干嘛呢?你想硬闯?!")
  }
})

注意(个人理解,不具有权威性)

到这里 Token 的生成、验证、检验不通过错误处理就完成了。 Token 生成一般是在登录之后生成,并返回给前端,前端拿到 Token ,并在每次请求 api 的时候携带上 Token , Token 就相当于这个用户的身份,不要轻易泄露。

Token一旦签发,不能主动让它失效,只能等待它有效期过才能失效。也就是说就算你修改了密码,之前的 Token 也还是有效的。你可以修改后端生成 Token 时使用的密钥,不让之前的 Token 检验通过,但是这就表示之前所有生成 Token 都失效了,做不到针对某个用户进行注销。这显然也不合适的。 所以用户修改密码时,前端一般都要清除之前保存的 Token,再重获取新的 Token

有朋友应该会想到在后端把 Token 储存起来,每一个用户对应一个 token。修改账号时,再生成一个新的 Token 覆盖之前的 Token,但这就违背了使用 Token 的目的,Token 的使用很大程度就为了减少服务器的压力。把尽可能多的信息存储在客户端而不是服务端。

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP