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

相關文章
相關標籤/搜索