egg.js+redis+postgresql实现一套基于jwt的sso单点登陆系统demo

最终目的

实现一套基于jwt方案的单点登陆系统,能够用于平时自身接外包作项目。javascript

总体逻辑

clipboard.png

技术准备

egg.js

前置知识

1.eggjs基于koa2,能够认为是koa2的框架层面的约束,须要有koa2基础,能够参考koa2文档
2.关于koa2洋葱圈模型的解析能够看这里
3.node版本8.x,能够很方便地使用async/await来写异步代码
4.egg.js官方文档html

目录结构以及框架约定

官方文档推荐传送门,不过咱们用不到这么多,一切以需求为主,只介绍用的到的地方,其余的功能能够之后慢慢摸索前端

├── package.json
├── app
|   ├── router.js
│   ├── controller
│   |   └── user.js
│   ├── service
│   |   └── user.js
│   ├── middleware
│   |   └── checkToken.js
│   └── model
│       └── user.js
├── config
|   ├── plugin.js
|   ├── config.default.js

以上就是框架约定的目录,因为咱们前端分离,因此view目录也不须要了:java

  • app/router.js 用于配置 URL 路由规则。
  • app/controller/** 用于解析用户的输入,处理后返回相应的结果。
  • app/service/** 用于编写业务逻辑层。
  • app/middleware/** 用于编写中间件。
  • config/config.{env}.js 用于编写配置文件。
  • config/plugin.js 用于配置须要加载的插件。

tips

修改cors

修改plugin.jsnode

exports.cors = {
    enable: true,
    package: 'egg-cors',
}

修改config.default.jsgit

exports.security = {
    csrf: {
        enable: false,
        ignoreJSON: true
    },
    domainWhiteList: ['*']
}

exports.cors = {
    origin: '*',
    allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH'
}

在egg.js中使用redis

安装请看redis在mac下的安装,其余操做系统请根据口味自行百度。github

使用请参考egg-redis文档web

Redis是什么redis

yarn add egg-redis

修改plugin.jssql

exports.redis = {
    enable: true,
    package: 'egg-redis',
}

修改config.default.js

exports.redis = {
    client: {
        port: [port],          
        host: '127.0.0.1',
        password: [password],
        db: 0
    }
}

注意点

  1. 必定要改默认端口!必定要改默认端口!必定要改默认端口! 请看:Redis 未受权访问缺陷可轻易致使系统被黑,请修改redis.conf: requirepass(密码) , port(端口)
  2. 可能会遇到redis快照关闭致使没法写入数据的状况,会报错,相似: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

在egg.js中使用postgresql

安装请看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'
}

生成token

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

后端业务逻辑

clipboard.png

前端业务逻辑

clipboard.png

中间件

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']
    }

clipboard.png

相关文章
相关标签/搜索