Bougie 2019-06-28
实现一套基于jwt方案的单点登录系统,可以用于平时自身接外包做项目。
1.eggjs基于koa2
,可以认为是koa2的框架层面的约束,需要有koa2基础,可以参考koa2文档
2.关于koa2洋葱圈模型的解析可以看这里
3.node版本8.x
,可以很方便地使用async/await来写异步代码
4.egg.js官方文档
官方文档推荐传送门,不过我们用不到这么多,一切以需求为主,只介绍用的到的地方,其他的功能可以以后慢慢摸索
├── package.json ├── app | ├── router.js │ ├── controller │ | └── user.js │ ├── service │ | └── user.js │ ├── middleware │ | └── checkToken.js │ └── model │ └── user.js ├── config | ├── plugin.js | ├── config.default.js
以上就是框架约定的目录,由于我们前端分离,所以view目录也不需要了:
修改plugin.js
exports.cors = { enable: true, package: 'egg-cors', }
修改config.default.js
exports.security = { csrf: { enable: false, ignoreJSON: true }, domainWhiteList: ['*'] } exports.cors = { origin: '*', allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH' }
安装请看redis在mac下的安装,其他操作系统请根据口味自行百度。
使用请参考egg-redis文档
yarn add egg-redis
修改plugin.js
exports.redis = { enable: true, package: 'egg-redis', }
修改config.default.js
exports.redis = { client: { port: [port], host: '127.0.0.1', password: [password], db: 0 } }
一定要改默认端口!一定要改默认端口!一定要改默认端口!
请看:Redis 未授权访问缺陷可轻易导致系统被黑,请修改redis.conf: requirepass
(密码) , port
(端口)MISCONF Redis is configured to save RDB snapshots, but it is currently not able to persist on disk. Commands that may modify the data set are disabled, because this instance is configured to report errors during writes if RDB snapshotting fails (stop-writes-on-bgsave-error option). Please check the Redis logs for details about the RDB error.
解决方案是修改redis.conf: stop-writes-on-bgsave-error
改为no
安装请看postgresql在mac下的安装,其他操作系统请根据口味自行百度。
使用请参考egg-sequelize文档
PostgreSQL 与 MySQL 相比,优势何在?
yarn add egg-sequelize yarn add pg pg-hstore
修改plugin.js
exports.sequelize = { enable: true, package: 'egg-sequelize' }
修改config.default.js
exports.sequelize = { dialect: 'postgres', database: 'postgres', host: 'localhost', port: '8888', username: 'postgres', password: '123456' }
yarn add jsonwebtoken
var jwt = require('jsonwebtoken'); var tokenKey = 'token key' var token = jwt.sign({ foo: 'bar' }, tokenKey); var decoded = jwt.verify(token, tokenKey); console.log(decoded.foo) // bar
egg.js是基于Koa2的,可以非常容易的引入 Koa 中间件生态。
在我们这个应用中,不是所有的请求都需要验证token,所以可以通过中间件来处理,下面我们就来写一个中间件。
app/model/checkToken.js
const { verify } = require('jsonwebtoken') const moment = require('moment') module.exports = options => { return async function checkToken(ctx, next) { const { jwtKey } = ctx.app.config.appConfig const {request: { path, header: {token} }} = ctx const {exclude=[]} = options let decodedJwt = {} try { if (exclude.indexOf(path.replace('/', '')) === -1) { // 需要token的接口 decodedJwt = verify(token, jwtKey) // token exp 超时 if(moment().isAfter(decodedJwt.exp)) { throw { code: -340, msg: 'token 过期' } } } else { //不需要token的接口 decodedJwt.exp = -1 } } catch (error) { ctx.app.logger.error('token error', error) if (error.code) { ctx.body = error } else { ctx.body = { code: -360, msg: 'token 错误' } } } if (decodedJwt.exp) { await next() } } }
修改config.default.js
exports.middleware = ['checkToken'] // 中间件会按顺序执行 // 中间件需要的配置项,可以通过app.config[${middlewareName}]访问 exports.checkToken = { exclude: ['login', 'signup'] }