导航菜单

  • 0.api
  • 0.Async
  • 0.module
  • 1.ES2015
  • 2.Promise
  • 3.Node
  • 4.NodeInstall
  • 5.REPL
  • 6.NodeCore
  • 7.module&NPM
  • 8.Encoding
  • 9.Buffer
  • 10.fs
  • 11.Stream-1
  • 11.Stream-2
  • 11.Stream-3
  • 11.Stream-4
  • 12-Network-2
  • 12.NetWork-3
  • 12.Network-1
  • 13.tcp
  • 14.http-1
  • 14.http-2
  • 15.compress
  • 16.crypto
  • 17.process
  • 18.yargs
  • 19.cache
  • 20.action
  • 21.https
  • 22.cookie
  • 23.session
  • 24.express-1
  • 24.express-2
  • 24.express-3
  • 24.express-4
  • 25.koa-1
  • 26.webpack-1-basic
  • 26.webpack-2-optimize
  • 26.webpack-3-file
  • 26.webpack-4.tapable
  • 26.webpack-5-AST
  • 26.webpack-6-sources
  • 26.webpack-7-loader
  • 26.webpack-8-plugin
  • 26.webpack-9-hand
  • 26.webpack-10-prepare
  • 28.redux
  • 28.redux-jwt-back
  • 28.redux-jwt-front
  • 29.mongodb-1
  • 29.mongodb-2
  • 29.mongodb-3
  • 29.mongodb-4
  • 29.mongodb-5
  • 29.mongodb-6
  • 30.cms-1-mysql
  • 30.cms-2-mysql
  • 30.cms-3-mysql
  • 30.cms-4-nunjucks
  • 30.cms-5-mock
  • 30.cms-6-egg
  • 30.cms-7-api
  • 30.cms-8-roadhog
  • 30.cms-9-yaml
  • 30.cms-10-umi
  • 30.cms-12-dva
  • 30.cms-13-dva-ant
  • 30.cms-14-front
  • 30.cms-15-deploy
  • 31.dva
  • 31.cms-13-dva-antdesign
  • 33.redis
  • 34.unittest
  • 35.jwt
  • 36.websocket-1
  • 36.websocket-2
  • 38.chat-api-1
  • 38.chat-api-2
  • 38.chat-3
  • 38.chat-api-3
  • 38.chat
  • 38.chat2
  • 38.chat2
  • 39.crawl-0
  • 39.crawl-1
  • 39.crawl-2
  • 40.deploy
  • 41.safe
  • 42.test
  • 43.nginx
  • 44.enzyme
  • 45.docker
  • 46.elastic
  • 47.oauth
  • 48.wxpay
  • index
  • 52.UML
  • 53.design
  • index
  • 54.linux
  • 57.ts
  • 56.react-ssr
  • 58.ts_react
  • 59.ketang
  • 59.ketang2
  • 61.1.devops-linux
  • 61.2.devops-vi
  • 61.3.devops-user
  • 61.4.devops-auth
  • 61.5.devops-shell
  • 61.6.devops-install
  • 61.7.devops-system
  • 61.8.devops-service
  • 61.9.devops-network
  • 61.10.devops-nginx
  • 61.11.devops-docker
  • 61.12.devops-jekins
  • 61.13.devops-groovy
  • 61.14.devops-php
  • 61.15.devops-java
  • 61.16.devops-node
  • 61.17.devops-k8s
  • 62.1.react-basic
  • 62.2.react-state
  • 62.3.react-high
  • 62.4.react-optimize
  • 62.5.react-hooks
  • 62.6.react-immutable
  • 62.7.react-mobx
  • 62.8.react-source
  • 63.1.redux
  • 63.2.redux-middleware
  • 63.3.redux-hooks
  • 63.4.redux-saga
  • 63.5.redux-saga-hand
  • 64.1.router
  • 64.2.router-connected
  • 65.1.typescript
  • 65.2.typescript
  • 65.3.typescript
  • 65.4.antd
  • 65.4.definition
  • 66-1.vue-base
  • 66-2.vue-component
  • 66-3.vue-cli3.0
  • 66-4.$message组件
  • 66-5.Form组件
  • 66-6.tree
  • 66-7.vue-router-apply
  • 66-8.axios-apply
  • 66-9.vuex-apply
  • 66-10.jwt-vue
  • 66-11.vue-ssr
  • 66-12.nuxt-apply
  • 66-13.pwa
  • 66-14.vue单元测试
  • 66-15.权限校验
  • 67-1-network
  • 68-2-wireshark
  • 7.npm2
  • 69-hooks
  • 70-deploy
  • 71-hmr
  • 72.deploy
  • 73.import
  • 74.mobile
  • 75.webpack-1.文件分析
  • 75.webpack-2.loader
  • 75.webpack-3.源码流程
  • 75.webpack-4.tapable
  • 75.webpack-5.prepare
  • 75.webpack-6.resolve
  • 75.webpack-7.loader
  • 75.webpack-8.module
  • 75.webpack-9.chunk
  • 75.webpack-10.asset
  • 75.webpack-11.实现
  • 76.react_optimize
  • 77.ts_ketang_back
  • 77.ts_ketang_front
  • 78.vue-domdiff
  • 79.grammar
  • 80.tree
  • 81.axios
  • 82.1.react
  • 82.2.react-high
  • 82.3.react-router
  • 82.4.redux
  • 82.5.redux_middleware
  • 82.6.connected
  • 82.7.saga
  • 82.8.dva
  • 82.8.dva-source
  • 82.9.roadhog
  • 82.10.umi
  • 82.11.antdesign
  • 82.12.ketang-front
  • 82.12.ketang-back
  • 83.upload
  • 84.graphql
  • 85.antpro
  • 86.1.uml
  • 86.2.design
  • 87.postcss
  • 88.react16-1
  • 89.nextjs
  • 90.react-test
  • 91.react-ts
  • 92.rbac
  • 93.tsnode
  • 94.1.JavaScript
  • 94.2.JavaScript
  • 94.3.MODULE
  • 94.4.EventLoop
  • 94.5.文件上传
  • 94.6.https
  • 94.7. nginx
  • 95.1. react
  • 95.2.react
  • 96.1.react16
  • 96.2.fiber
  • 96.3.fiber
  • 97.serverless
  • 98.websocket
  • 100.1.react-basic
  • 101.1.monitor
  • 101.2.monitor
  • 102.java
  • 103.1.webpack-usage
  • 103.2.webpack-bundle
  • 103.3.webpack-ast
  • 103.4.webpack-flow
  • 103.5.webpack-loader
  • 103.6.webpack-tapable
  • 103.7.webpack-plugin
  • 103.8.webpack-optimize1
  • 103.9.webpack-optimize2
  • 103.10.webpack-hand
  • 103.11.webpack-hmr
  • 103.11.webpack5
  • 103.13.splitChunks
  • 103.14.webpack-sourcemap
  • 103.15.webpack-compiler1
  • 103.15.webpack-compiler2
  • 103.16.rollup.1
  • 103.16.rollup.2
  • 103.16.rollup.3
  • 103.16.vite.basic
  • 103.16.vite.source
  • 103.16.vite.plugin
  • 103.16.vite.1
  • 103.16.vite.2
  • 103.17.polyfill
  • 104.1.binary
  • 104.2.binary
  • 105.skeleton
  • 106.1.react
  • 106.2.react_hooks
  • 106.3.react_router
  • 106.4.redux
  • 106.5.redux_middleware
  • 106.6.connected-react-router
  • 106.6.redux-first-history
  • 106.7.redux-saga
  • 106.8.dva
  • 106.9.umi
  • 106.10.ketang
  • 106.11.antdesign
  • 106.12.antpro
  • 106.13.router-6
  • 106.14.ssr
  • 106.15.nextjs
  • 106.16.1.cms
  • 106.16.2.cms
  • 106.16.3.cms
  • 106.16.4.cms
  • 106.16.mobx
  • 106.17.fomily
  • 107.fiber
  • 108.http
  • 109.1.webpack_usage
  • 109.2.webpack_source
  • 109.3.dll
  • 110.nest.js
  • 111.xstate
  • 112.Form
  • 113.redux-saga
  • 114.react+typescript
  • 115.immer
  • 116.pro5
  • 117.css-loader
  • 118.1.umi-core
  • 119.2.module-federation
  • 119.1.module-federation
  • 120.create-react-app
  • 121.react-scripts
  • 122.react-optimize
  • 123.jsx-runtime
  • 124.next.js
  • 125.1.linux
  • 125.2.linux-vi
  • 125.3.linux-user
  • 125.4.linux-auth
  • 125.5.linux-shell
  • 125.6.linux-install
  • 125.7.linux-system
  • 125.8.linux-service
  • 125.9.linux-network
  • 125.10.nginx
  • 125.11.docker
  • 125.12.ci
  • 125.13.k8s
  • 125.14.k8s
  • 125.15.k8s
  • 125.16.k8s
  • 126.11.react-1
  • 126.12.react-2
  • 126.12.react-3
  • 126.12.react-4
  • 126.12.react-5
  • 126.12.react-6
  • 126.12.react-7
  • 126.12.react-8
  • 127.frontend
  • 128.rollup
  • 129.px2rem-loader
  • 130.health
  • 131.hooks
  • 132.keepalive
  • 133.vue-cli
  • 134.react18
  • 134.2.react18
  • 134.3.react18
  • 135.function
  • 136.toolkit
  • 137.lerna
  • 138.create-vite
  • 139.cli
  • 140.antd
  • 141.react-dnd
  • 142.1.link
  • 143.1.gulp
  • 143.2.stream
  • 143.3.gulp
  • 144.1.closure
  • 144.2.v8
  • 144.3.gc
  • 145.react-router-v6
  • 146.browser
  • 147.lighthouse
  • 148.1.basic
  • 148.2.basic
  • 148.3.basic
  • 148.4.basic
  • 148.5.basic
  • 149.1.vite
  • 149.2.vite
  • 149.3.vite
  • 149.4.vite
  • 150.react-window
  • 151.react-query
  • 152.useRequest
  • 153.transition
  • 154.emotion
  • 155.1.formily
  • 155.2.formily
  • 155.3.formily
  • 155.3.1.mobx.usage
  • 155.3.2.mobx.source
  • 156.vue-loader
  • 103.11.mf
  • 157.1.react18
  • 158.umi4
  • 159.rxjs
  • 159.rxjs2
  • 160.bff
  • 161.zustand
  • 162.vscode
  • 163.emp
  • 164.cors
  • 1.初始化项目
  • 2.使用MYSQL
    • 2.1 数据库脚本
    • 2.2 在egg使用mysql
  • 3. 用户管理
    • 3.1 app/router.js
    • 3.2 controller/user.js
    • 3.3 service/user.js
  • 4. 提取基类
    • 4.1 app/controller/api.js
    • 4.2 app/controller/base.js
    • 4.3 app/service/base.js
    • 4.4 controller/user.js
    • 4.5 service/user.js
  • 5. 角色
    • 5.1 app/router.js
    • 5.2 controller/role.js
    • 5.3 app/service/role.js
  • 6. 其它功能
    • 6.1 app/controller/api.js
    • 6.2 app/controller/base.js
    • 6.3 app/router.js
    • 6.4 service/base.js
    • 6.5 controller/resource.js
    • 6.6 controller/roleResource.js
    • 6.7 controller/roleUser.js
    • 6.8 app/service/resource.js
    • 6.9 service/roleResource.js
    • 6.10 app/service/roleUser.js
  • 7. 权限管理
    • 7.1 controller/role.js
    • 7.2 service/role.js
    • 7.3 app/router.js
  • 8. 验证码
    • 8.1 app/router.js
    • 8.2 controller/index.js
  • 9. 跨域
    • 9.1 config/config.default.js
    • 9.2 config/plugin.js
  • 10. 注册登录
    • 10.1 app/controller/user.js
    • 10.2 config.default.js
    • 10.3 app/middleware/auth.js
    • 10.4 app/router.js
  • 11.使用 VSCode 进行调试
  • 12. 参考

1.初始化项目 #

$ npm i egg-init -g
$ egg-init cms-api --type=simple
$ cd cms-api
$ npm i
$ npm run dev

2.使用MYSQL #

2.1 数据库脚本 #

CREATE TABLE user (
 id int(11) PRIMARY KEY AUTO_INCREMENT,
 username varchar(255) NULL,
 password varchar(255) NULL,
 email varchar(255) NULL,
 phone varchar(255) NULL,
 gender tinyint(255) NULL,
 birthday datetime NULL,
 address varchar(255) NULL
);

CREATE TABLE role (
 id int(11) PRIMARY KEY AUTO_INCREMENT,
 name varchar(255) NULL
);

CREATE TABLE role_user (
role_id int(11) NOT NULL,
user_id int(11) NOT NULL,
PRIMARY KEY (user_id, role_id) 
);

CREATE TABLE resource (
id int(11) PRIMARY KEY AUTO_INCREMENT,
name varchar(255) NOT NULL
);

CREATE TABLE role_resource (
role_id int(11) NOT NULL,
resource_id int(255) NOT NULL,
PRIMARY KEY (role_id, resource_id) 
);

2.2 在egg使用mysql #

cnpm i egg-mysql -S

config/config.default.js

config.security = {
    csrf:false
} 
config.mysql = {
    // 单数据库信息配置
    client: {
      // host
      host: 'localhost',
      // 端口号
      port: '3306',
      // 用户名
      user: 'root',
      // 密码
      password: 'root',
      // 数据库名
      database: 'cms',
}

config/plugin.js

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

3. 用户管理 #

  • restful-风格的-url-定义

3.1 app/router.js #

module.exports = app => {
  const { router, controller } = app;
  router.get('/',controller.home.index);
  router.resources('user', '/api/user', controller.user);
};

3.2 controller/user.js #

app/controller/user.js

const {Controller} = require('egg');
class UserController extends Controller {
  async index() {
    let {ctx,service}=this;
    let users=await service.user.select();
    ctx.body = users;
  }

  async create() {
    let {ctx,service}=this;
    let user=ctx.request.body;
    await service.user.create(user);
    ctx.body={
      code: 0,
      data:'success!'
    }
  }

  async update() {
    let {ctx,service}=this;
    let user=ctx.request.body;
    user.id=ctx.params.id;
    let savedUser=await service.user.update(user);
    ctx.body={
      code: 0,
      data:'success!'
    }
  }
  async destroy() {
    let {ctx,service}=this;
    let id=ctx.params.id;
    await service.user.delete(id);
    ctx.body={
      code: 0,
      data:'success!'
    }
  }
}

module.exports = UserController;

3.3 service/user.js #

app/service/user.js

const {Service}=require('egg');
class UserService extends Service{
    async select() {
        return await this.app.mysql.select('user');
    }
    async create(entity) {
        return await this.app.mysql.insert('user',entity);
    }
    async update(entity) {
        return await this.app.mysql.update('user',entity);
    }
    async delete(id) {
        return await this.app.mysql.delete('user',{id});
    }
}
module.exports=UserService;

4. 提取基类 #

4.1 app/controller/api.js #

app/controller/api.js

const BaseController = require('./base');
class ApiController extends BaseController {
    async index() {
    let {ctx,service}=this;
    let list=await service[this.entity].select();
    ctx.body = list;
  }

  async create() {
    let {ctx,service}=this;
    let user=ctx.request.body;
    await service[this.entity].create(user);
    ctx.body={
      code: 0,
      data:'success!'
    }
  }

  async update() {
    let {ctx,service}=this;
    let user=ctx.request.body;
    user.id=ctx.params.id;
    await service[this.entity].update(user);
    ctx.body={
      code: 0,
      data:'success!'
    }
  }
  async destroy() {
    let {ctx,service}=this;
    let id=ctx.params.id;
    await service[this.entity].delete(id);
    ctx.body={
      code: 0,
      data:'success!'
    }
  }
}
module.exports=ApiController;

4.2 app/controller/base.js #

app/controller/base.js

const Controller = require('egg').Controller;
class BaseController extends Controller {
    success(data) {
        let {ctx}=this;
        ctx.body={
            code: 0,
            data
        }
    }
    error(error) {
        let {ctx}=this;
        ctx.status=404;
        ctx.body={
            code: 1,
            error
        }
    }
}
module.exports=BaseController;

4.3 app/service/base.js #

app/service/base.js

const {Service}=require('egg');
class BaseService extends Service{
    async select() {
        return await this.app.mysql.select(this.entity);
    }
    async create(entity) {
        return await this.app.mysql.insert(this.entity,entity);
    }
    async update(entity) {
        return await this.app.mysql.update(this.entity,entity);
    }
    async delete(id) {
        return await this.app.mysql.delete(this.entity,{id});
    }
}
module.exports=BaseService;

4.4 controller/user.js #

app/controller/user.js

const ApiController = require('./api');
class UserController extends ApiController {
  constructor(...args) {
    super(...args);
    this.entity='user';
  }
}

module.exports = UserController;

4.5 service/user.js #

app/service/user.js

const BaseService = require('./base');
class UserService extends BaseService{
    constructor(...args) {
        super(...args);
        this.entity='user';
    }
}
module.exports=UserService;

5. 角色 #

5.1 app/router.js #

app/router.js

+ router.resources('role', '/api/role', controller.role);

5.2 controller/role.js #

app/controller/role.js

const ApiController = require('./api');
class RoleController extends ApiController {
  constructor(...args) {
    super(...args);
    this.entity='role';
  }
}

module.exports = RoleController;

5.3 app/service/role.js #

app/service/role.js

const BaseService = require('./base');
class RoleService extends BaseService{
    constructor(...args) {
        super(...args);
        this.entity='role';
    }
}
module.exports=RoleService;

6. 其它功能 #

  • 实现分页功能
  • 根据数据库操作返回值来判断操作是成功还是失败

6.1 app/controller/api.js #

const BaseController = require('./base');
class ApiController extends BaseController {
    async index() {
    const {ctx,service}=this;
    const {pageNum,pageSize,...where}=ctx.query;
    let result=await service[this.entity].list(isNaN(pageNum)?1:parseInt(pageNum),isNaN(pageSize)?this.config.PAGE_SIZE:parseInt(pageSize),where);
    this.success(result);
  }

  async create() {
    let {ctx,service}=this;
    let user=ctx.request.body;
    let result = await service[this.entity].create(user);
    result>0? this.success('添加成功'):this.error('添加失败');
  }

  async update() {
    let {ctx,service}=this;
    let user=ctx.request.body;
    user.id=ctx.params.id;
    let result = await service[this.entity].update(user);
    result>0? this.success('更新成功'):this.error('更新失败');
  }
  async destroy() {
    let {ctx,service}=this;
    let id=ctx.params.id;
    let ids=ctx.request.body;
    if (!ids) {ids=[id]}
    let result = await service[this.entity].delete(ids);
    result>0? this.success('删除成功'):this.error('删除失败');
  }
}
module.exports=ApiController;

6.2 app/controller/base.js #

app/controller/base.js

const Controller = require('egg').Controller;
class BaseController extends Controller {
    success(data) {
        let {ctx}=this;
        ctx.body={
            code: 0,
            data
        }
    }
    error(error) {
        let {ctx}=this;
        ctx.status=500;
        ctx.body={
            code: 1,
            error
        }
    }
}
module.exports=BaseController;

6.3 app/router.js #

app/router.js

module.exports = app => {
  const { router, controller } = app;
  router.get('/',controller.home.index);
  router.resources('user','/api/user',controller.user);
  router.resources('role','/api/role',controller.role);
  router.resources('resource', '/api/resource', controller.resource);
  router.resources('roleUser', '/api/roleUser', controller.roleUser);
  router.resources('roleResource', '/api/roleResource', controller.roleResource);
};

6.4 service/base.js #

app/service/base.js

const {Service}=require('egg');
class BaseService extends Service{
    async list(pageNum,pageSize,where) {
        const {app} = this;
        const list=await app.mysql.select(this.entity,{
            where,
            order: [['id','desc']],
            offset: (pageNum-1)*pageSize,
            limit :pageSize
        });
        const total=await app.mysql.count(this.entity,where);
    //返回当页的数据和总记录数
        return {list,total};
    }
    async create(entity) {
        const {app}=this;
        let result=await app.mysql.insert(this.entity,entity);
        const affectedRows=result.affectedRows;
        return affectedRows;
    }
    async update(entity) {
        const {app}=this;
        let result = await app.mysql.update(this.entity,entity);
        const affectedRows=result.affectedRows;
        return affectedRows;
    }
    async delete(ids) {
        const {app}=this;
        let result = await app.mysql.delete(this.entity,{id:ids});
        const affectedRows=result.affectedRows;
        return affectedRows;
    }
}
module.exports=BaseService;

6.5 controller/resource.js #

app/controller/resource.js

const ApiController = require('./api');
class ResourceController extends ApiController {
  constructor(...args) {
    super(...args);
    this.entity='resource';
  }
}
module.exports = ResourceController;

6.6 controller/roleResource.js #

app/controller/roleResource.js

const ApiController = require('./api');
class RoleResourceController extends ApiController {
  constructor(...args) {
    super(...args);
    this.entity='roleResource';
  }
}
module.exports = RoleResourceController;

6.7 controller/roleUser.js #

app/controller/roleUser.js

const ApiController = require('./api');
class RoleUserController extends ApiController {
  constructor(...args) {
    super(...args);
    this.entity='roleUser';
  }
}

module.exports = RoleUserController;

6.8 app/service/resource.js #

service/resource.js

const BaseService = require('./base');
class ResourceService extends BaseService{
    constructor(...args) {
        super(...args);
        this.entity='resource';
    }
}
module.exports=ResourceService;

6.9 service/roleResource.js #

app/service/roleResource.js

const BaseService = require('./base');
class roleResourceService extends BaseService{
    constructor(...args) {
        super(...args);
        this.entity='role_resource';
    }
}
module.exports=roleResourceService;

6.10 app/service/roleUser.js #

app/service/roleUser.js

const BaseService = require('./base');
class roleUserService extends BaseService{
    constructor(...args) {
        super(...args);
        this.entity='role_user';
    }
}
module.exports=roleUserService;

7. 权限管理 #

7.1 controller/role.js #

app/controller/role.js

const ApiController = require('./api');
class RoleController extends ApiController {
  constructor(...args) {
    super(...args);
    this.entity='role';
  }

  async getResource() {
    const { app, ctx, service } = this;
    const result = await service[this.entity].getResource();
    ctx.body = result;
  }
  async setResource() {
    const { app, ctx, service } = this;
    let body = ctx.request.body;//{roleId,resourceIds
    const result = await service[this.entity].setResource(body);
    ctx.body = result;
  }
  async getUser() {
    const { app, ctx, service } = this;
    const result = await service[this.entity].getUser();
    ctx.body = result;
  }
  async setUser() {
    const { app, ctx, service } = this;
    let body = ctx.request.body;//{roleId,userIds}
    const result = await service[this.entity].setUser(body);
    ctx.body = result;
  }
}

module.exports = RoleController;

7.2 service/role.js #

app/service/role.js

const BaseService = require('./base');
class RoleService extends BaseService{
    constructor(...args) {
        super(...args);
        this.entity='role';
    }
    async list(pageNum, pageSize, where) {
        const { app } = this;
        const list = await app.mysql.select(this.entity, {
          where,
          orders: [['id', 'desc']],
          offset: (pageNum - 1) * pageSize,
          limit: pageSize,
        });
        //list  resourceIds=代表这个角色所拥有的资源ID数组
        for (let i = 0; i < list.length; i++) {
          let rows = await app.mysql.select('role_resource', {
            where: { role_id: list[i].id }
          });//[{role_id:1,resource_id:2},{role_id:1,resource_id:3}]
          list[i].resourceIds = rows.map(item => item.resource_id);//[2,3]

          rows = await app.mysql.select('role_user', {
            where: { role_id: list[i].id }
          });//[{role_id:1,resource_id:2},{role_id:1,resource_id:3}]
          list[i].userIds = rows.map(item => item.user_id);//[2,3]
        }
        //count用来统计总条数
        const total = await app.mysql.count(this.entity, where);
        return { list, total };
    }
    async getResource() {
        const { app } = this;
        const list = await app.mysql.select('resource');
        let rootMenus = [];
        let map = {};
        list.forEach(item => {
          item.children = [];
          map[item.id] = item;//创建了一个Key-Value,key就是对象的ID,值就是对象本身
          if (item.parent_id == 0) {
              rootMenus.push(item);
          } else {
               map[item.parent_id].children.push(item)
          }
        });
        return rootMenus;
      }
    async setResource(values) {
      const {app} = this;
      let {roleId,resourceIds} = values;
      const conn = await app.mysql.beginTransaction(); // 初始化事务
      try {
         //1.先删除 所有的关联记录 DELETE FROM role_resource WHERE role_id =1
          await conn.query(`DELETE FROM role_resource WHERE role_id = ?`,[roleId]);
          //2.插入新的关联记录
          for(let i=0;i<resourceIds.length;i++){
            let resourceId = resourceIds[i];
            await conn.insert('role_resource',{role_id:roleId,resource_id:resourceId});
          }
        await conn.commit(); // 提交事务
      } catch (err) {
        // error, rollback
        await conn.rollback(); // 一定记得捕获异常后回滚事务!!
        throw err;
      }
      return '修改权限成功!'
  }
    async getUser() {
        const { app } = this;
        const list = await app.mysql.select('user');
        return list;
      }
    async setUser(values){
      const {app} = this;
      let {roleId,userIds} = values;
      const conn = await app.mysql.beginTransaction(); // 初始化事务
      try {
         //1.先删除 所有的关联记录 DELETE FROM role_user WHERE role_id=1
          await conn.query(`DELETE FROM role_user WHERE role_id=?`,[roleId]);
          //2.插入新的关联记录
          for(let i=0;i<userIds.length;i++){
            let userId = userIds[i];
            await conn.insert('role_user',{role_id:roleId,user_id:userId});
          }
        await conn.commit(); // 提交事务
      } catch (err) {
        // error, rollback
        await conn.rollback(); // 一定记得捕获异常后回滚事务!!
        throw err;
      }

      return '给角色分配用户成功!'
    }

}
module.exports=RoleService;

7.3 app/router.js #

app/router.js

router.post('/role/setUser', controller.role.setUser);
router.get('/role/getUser', controller.role.getUser);
router.post('/role/setResource', controller.role.setResource);
router.get('/role/getResource', controller.role.getResource);

8. 验证码 #

  • svg-captcha

    8.1 app/router.js #

    app/router.js
    router.get('/captcha',controller.index.captcha);

    8.2 controller/index.js #

    app/controller/index.js
    const BaseController=require('./base');
    const svgCaptcha = require('svg-captcha');
    class IndexController extends BaseController {
      async captcha() {
      let {ctx}=this;
      var captcha=svgCaptcha.create({});
      ctx.session.captcha=captcha.text;
      ctx.set('Content-Type','image/svg+xml');
      ctx.body=captcha.data;
    }
    }
    module.exports=IndexController;

    9. 跨域 #

  • 跨域传cookie的时候要求主域要一致,不能从localhost跨到127.0.0.1
  • egg-cors

9.1 config/config.default.js #

config/config.default.js

config.security = {
    csrf: false,
    domainWhiteList: [ 'http://127.0.0.1:8000' ]
} 

9.2 config/plugin.js #

config/plugin.js

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

10. 注册登录 #

10.1 app/controller/user.js #

app/controller/user.js

const ApiController = require('./api');
const {sign} = require('jsonwebtoken');
class UserController extends ApiController {
  constructor(...args) {
    super(...args);
    this.entity = 'user';
  }

   async signin() {
    let {ctx,app} = this;
    let body = ctx.request.body;
    const result = await app.mysql.select('user', {where: {username: body.username,password: body.password},
      limit: 1,
      offset: 0
    });
    if (result && result.length > 0) {
      let user = JSON.parse(JSON.stringify(result[0]));
      let list = await app.mysql.query(`SELECT resource.* FROM role_user,role_resource,resource where role_user.role_id = role_resource.role_id AND role_resource.resource_id = resource.id AND role_user.user_id = ? ORDER BY resource.id ASC`,[user.id]);
      let resources = [];
      let map = {};
      list.forEach(item => {
          item.children = [];
          map[item.id] = item;
          if (item.parent_id == 0) {
            resources.push(item);
          } else {
            map[item.parent_id].children.push(item);
          }
      });
      user.resources=resources;
      this.success(sign(user, this.config.jwtSecret));
    } else {
      this.error('登录失败');
    }
  }
  async signup() {
    let {ctx,app} = this;
    const { agreement, prefix, phone, address, repassword, captcha, ...user } = ctx.request.body;
    if (!agreement) {
      return this.error('请同意协议再注册!');
    }
    if (user.password !== repassword) {
      return this.error('密码和确认密码不一致!');
    }
    if (!captcha || !ctx.session.captcha || captcha.toLowerCase() !== ctx.session.captcha.toLowerCase()) {
      //return this.error('验证码不正确!');
    }
    user.phone = prefix + '-' + phone;
    user.address = address.join('-');
    const result = await app.mysql.insert('user', user);
    if (result.affectedRows > 0) {
      this.success({
        id: result.insertId,
      });
    } else {
      this.error('注册失败');
    }
  }
}

module.exports = UserController;

10.2 config.default.js #

config/config.default.js

config.security = {
    csrf: false,
    domainWhiteList: [ 'http://localhost:8000' ]
} 
config.jwtSecret="zfpx";
config.cors = {
    credentials: true
}

10.3 app/middleware/auth.js #

app/middleware/auth.js

let {verify}=require('jsonwebtoken');
function verifyToken(token,jwtSecret) {
    return new Promise(function (resolve,reject) {
        verify(token,jwtSecret,async (err,data) => {
            if (err) {
                reject(err);
            } else {
                resolve(data);
            }
        });
    });
}
module.exports=(options,app) => {
    return async function (ctx,next) {
        const token=ctx.get('authorization');
        if (token) {
            try {
                let user = await verifyToken(token,app.config.jwtSecret);
                ctx.session.user=user;
                await next();
            } catch (err) {
                ctx.status=401;
                ctx.body={
                    code: 1,
                    error:'token验证失败'
                }
            }
        } else {
            ctx.status=401;
                ctx.body={
                    code: 1,
                    error:'请提供token'
                }
        }
    }
}

10.4 app/router.js #

app/router.js

  const auth=app.middleware.auth({},app);
  router.post('/api/signin',controller.user.signin);
  router.post('/api/signup',controller.user.signup);
  router.get('/captcha',controller.index.captcha);
  router.get('/',controller.home.index);
  router.post('/role/setUser', controller.role.setUser);
  router.get('/role/getUser', controller.role.getUser);
  router.post('/role/setResource', controller.role.setResource);
  router.get('/role/getResource', controller.role.getResource);
  router.resources('user','/api/user',auth,controller.user);
  router.resources('role','/api/role',auth,controller.role);
  router.resources('resource', '/api/resource', auth,controller.resource);
  router.resources('roleUser', '/api/roleUser', auth,controller.roleUser);
  router.resources('roleResource', '/api/roleResource', auth,controller.roleResource);

11.使用 VSCode 进行调试 #

  • 使用-egg-bin-调试
  • 方式一:开启 VSCode 配置 Debug: Toggle Auto Attach,然后在 Terminal 执行 npm run debug 即可。
  • 方式二:配置 VSCode 的 .vscode/launch.json,然后 F5 一键启动即可。(注意,需要关闭方式一中的配置)
// .vscode/launch.json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Launch Egg",
      "type": "node",
      "request": "launch",
      "cwd": "${workspaceRoot}",
      "runtimeExecutable": "npm",
      "windows": { "runtimeExecutable": "npm.cmd" },
      "runtimeArgs": [ "run", "debug" ],
      "console": "integratedTerminal",
      "protocol": "auto",
      "restart": true,
      "port": 9229,
      "autoAttachChildProcesses": true
    }
  ]
}

12. 参考 #

  • restful
  • egg-cors
  • svg-captcha

访问验证

请输入访问令牌

Token不正确,请重新输入