koa2使用jwt鉴权

文章发布于2020年11月09日 13:48, 归类于: Node.js

鉴权

对用户进行认证,是否拥有访问权。

此示例,鉴定的是用户是否有权访问某个接口(路由)。

认证方式

此示例使用 jwt 认证方式。jwt 是 json web token 的缩写。

jwt

jwt 由三个部分组成:

Header(头部) Payload(负载) Signature(签名)

生成token发给用户时是这样的Header.Payload.Signature格式。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InJvamVyeW9uZyIsImlhdCI6MTYwMjYzNzYyOSwiZXhwIjoxNjAyNjM3NzQ5fQ.NdDjdFqTB1RrMGDQN1fy7a3prZdYuOPjGYM05qrXjyU

《JSON Web Token 入门教程》:http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html

步骤

1、用户登录成功,后台使用jsonwebtoken生成签名(token)发给用户。 2、用户请求接口时,需要在请求头(或在请求体中、url参数中、cookie中)携带签名(token),后台使用koa-jwt做鉴权。

安装

https://github.com/auth0/node-jsonwebtoken

https://github.com/koajs/jwt

npm i jsonwebtoken
npm i koa-jwt

使用

1、生成 token

用户登录成功,生成 token 返回给用户。

const jsonwebtoken = require('jsonwebtoken');
const jwtSecret = '123456' // 密钥
const token = null

// 生成签名
jsonwebtoken.sign({ username: 'rojeryong' }, jwtSecret, { algorithm: 'HS256', expiresIn: '120s' }, function (err, jwtToken) {
  if (!err) {
    token = jwtToken
  }
});

username:自定义内容。 jwtSecret:生成签名的密钥。 algorithm:加密方式。 expiresIn:有效期,数字,秒,也可以设置1d代表一天,1h代表一小时... function:回调。

如果不想使用 koajwt 鉴权,可以使用 jsonwebtoken.verify 自定义鉴权中间件来做鉴权,自定义鉴权可能比 koajwt 鉴权更灵活。

jsonwebtoken.verify(token, jwtSecret, function (err, decoded) {
  if (err) {
    // 不通过
    console.log(JSON.stringify(err))
  }else {
    // 通过
    console.log(decoded)
  }
});

2、koajwt 全局鉴权

jsonwebtoken 使用纯数字类型密钥可能会报错,建议使用字符类型。

// app.js
const Koa = require('koa')
const app = new Koa()
const router = require('koa-router')()
const koaJwt = require('koa-jwt');
const jwtSecret = '123456' // 密钥,字符,使用数字类型可能会报错

// 静态目录
app.use(require('koa-static')(__dirname + '/public'), {
  maxage: 30 * 24 * 60 * 60 * 1000, // 浏览器缓存时间
  extensions: ['html'] // 开启html静态访问
})

// 从url、body 或者 cookie 中获取 token
app.use(async (ctx, next) => {
  // url,body 的 token
  let params = Object.assign({}, ctx.request.query, ctx.request.body);
  // 请求头的 token
  let token = ctx.request.header && ctx.request.header.authorization?ctx.request.header.authorization:(params.token?params.token:null)
   // cookie 的token
  if(!token) {
    token = ctx.cookies.get('token') || null;
  }
  // 设置头部
  ctx.request.header = { 'authorization': "Bearer " + token }
  await next();
})

// 错误监听
app.use(async (ctx, next) => {
    return next().catch((err) => {
        if (err.status === 401) {
            let message = err.originalError && err.originalError.message ? err.originalError.message : (err.message ? err.message : "Authentication Error")
            ctx.throw(401, message)
        } else {
            throw err;
        }
    })
});

// 鉴权
app.use(koaJwt({ secret: jwtSecret }).unless({
  // 放行的路由
  path: ['/','/login','/favicon.ico',new RegExp(`^/hello`)]
}))

// 放行的路由
router.get('/', async (ctx, next) => {
  ctx.response.body = '<h1>index page</h1>'
})

// 放行的路由
router.get('/login', async (ctx, next) => {
    ctx.response.body = '<h1>login page</h1>'
})

router.get('/admin', async (ctx, next) => {
    ctx.response.body = '<h1>admin page</h1>'
})

app.use(router.routes())

app.listen(4000, () => {
  console.log('app started at port 127.0.0.1:4000...');
});

注意

app.use(koaJwt({ secret: jwtSecret }).unless({
  // 放行的路由
  path: ['/','/login','/favicon.ico',new RegExp(`^/hello`)]
}))

path:不需要鉴权的路由(开放访问的路由)。

优先获取请求头ctx.request.header.authorization的 token,没有的话获取 body、url 参数或 cookie 的 token。

如果鉴权不通过,可以在错误监听回调里面处理错误,可以配合koa-onerror使用。

错误监听代码应该写在鉴权代码之前,洋葱模型,发生错误后是不会继续往下执行的。

注意鉴权代码的位置,鉴权代码应该写在注册路由之前,写在koa-static(用了的话)等中间件之后,否则,请求静态资源路径也被鉴权。

测试

运行app.js,分别访问以下路由。

http://localhost:4000

http://localhost:4000/login

http://localhost:4000/admin

除了放行的路由,如果不传 token 会提示错误。

携带 token 访问

在请求需要验证的路由时,在 body、url 或者 cookie 携带 token 即可。

ajax 请求时携带 token:

const axios = require('axios');
let option = {
  method: 'get',
  url: `http://localhost:4000/admin`,
  params:{
    token:'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InVzZXIuaWQiLCJpYXQiOjE2MDQ4OTM5NDYsImV4cCI6ODgwMDQ4MDc1NDZ9.e-DgPVoRIWXsQDi9RPp3cy6cweTrY-oo8bWLd163yxY'
  }
}

await axios(option).then(res => {
  if (res.status == 200) {
   // ...
  }
})

url 携带 tokn:

http://localhost:4000/admin?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InVzZXIuaWQiLCJpYXQiOjE2MDQ4OTM5NDYsImV4cCI6ODgwMDQ4MDc1NDZ9.e-DgPVoRIWXsQDi9RPp3cy6cweTrY-oo8bWLd163yxY

koa2 后端给前端设置 cookie:

// 后端代码
let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InVzZXIuaWQiLCJpYXQiOjE2MDQ4OTM5NDYsImV4cCI6ODgwMDQ4MDc1NDZ9.e-DgPVoRIWXsQDi9RPp3cy6cweTrY-oo8bWLd163yxY"
ctx.cookies.set('token', token)

前端访问路由时会自动携带 token。

转载请注明来源:《 koa2使用jwt鉴权》- rojerYong's Blog

文章链接:https://www.eoway.cn/article/1604900889.html

如果此文摘取了你的原创,请联系本站管理员,将对此文修改、删除处理。

--END--
上一篇:js判断是否ie浏览器、ie浏览器版本 下一篇:uniapp 设置 APP 首次打开时显示“用户协议和隐私政策”弹框