用户管理
1.1 app/controller/base.js [#](#t11.1 app/controller/base.js)
app/controller/base.js
const {Controller} = require('egg');
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;
1.2 app/controller/restful.js [#](#t21.2 app/controller/restful.js)
app/controller/restful.js
const Service = require('egg').Service;
// ctx,app,service,config,logger
class ApiService extends Service {
constructor(...args) {
super(...args);
}
async select() {
return await this.app.mysql.select(this.model);
}
async get(id) {
return await this.app.mysql.get(this.model,{id});
}
async insert(entity) {
return await this.app.mysql.insert(this.model,entity);
}
async update(entity) {
return await this.app.mysql.update(this.model,entity);
}
async delete(id) {
return await this.app.mysql.delete(this.model,{id});
}
}
module.exports = ApiService;
1.3 app/controller/users.js [#](#t31.3 app/controller/users.js)
app/controller/users.js
'use strict';
const ApiController = require('./restful');
class UserController extends ApiController {
constructor(...args) {
super(...args);
this.model='users';
}
}
module.exports = UserController;
1.4 app/router.js [#](#t41.4 app/router.js)
app/router.js
module.exports = app => {
const { router, controller } = app;
router.get('/', controller.home.index);
router.resources('users', '/users', controller.users);
};
1.5 app/service/restful.js [#](#t51.5 app/service/restful.js)
app/service/restful.js
const Service = require('egg').Service;
// ctx,app,service,config,logger
class ApiService extends Service {
constructor(...args) {
super(...args);
}
async select() {
return await this.app.mysql.select(this.model);
}
async get(id) {
return await this.app.mysql.get(this.model,{id});
}
async insert(entity) {
return await this.app.mysql.insert(this.model,entity);
}
async update(entity) {
return await this.app.mysql.update(this.model,entity);
}
async delete(id) {
return await this.app.mysql.delete(this.model,{id});
}
}
module.exports = ApiService;
1.6 app/service/users.js [#](#t61.6 app/service/users.js)
app/service/users.js
const ApiService=require('./restful');
// ctx,app,service,config,logger
class UsersService extends ApiService {
constructor(...args) {
super(...args);
this.model='users';
}
}
module.exports = UsersService;
1.7 config/config.default.js [#](#t71.7 config/config.default.js)
config/config.default.js
'use strict';
module.exports = appInfo => {
const config = exports = {};
// use for cookie sign key, should change to your own and keep security
config.keys = appInfo.name + '_1532576284179_9329';
// add your config here
config.middleware=[];
config.security = {
csrf: false
}
exports.mysql = {
// 单数据库信息配置
client: {
// host
host: 'localhost',
// 端口号
port: '3306',
// 用户名
user: 'root',
// 密码
password: '',
// 数据库名
database: 'cms',
},
// 是否加载到 app 上,默认开启
app: true,
// 是否加载到 agent 上,默认关闭
agent: false,
};
config.logger={
appLogName: `${appInfo.name}-web.log`,
coreLogName: 'egg-web.log',
agentLogName: 'egg-agent.log',
errorLogName: 'common-error.log',
level: 'DEBUG',
}
return config;
};
1.8 config/plugin.js [#](#t81.8 config/plugin.js)
config/plugin.js
exports.mysql = {
enable: true,
package: 'egg-mysql',
};
1.9 users.test.js [#](#t91.9 users.test.js)
test/app/controller/users.test.js
const { app, assert } = require('egg-mock/bootstrap');
const querystring=require('querystring');
const _=require('lodash');
const uuid=require('uuid');
describe('test/app/controller/users.test.js', () => {
let initialSize;
let insertId;
let username=uuid.v4();
let newUser={
username: username,
password: username,
email: `${username}@qq.com`,
phone: username,
gender: 1,
birthday:'2018-09-09',
address:'回龙观'
}
it('should GET /users',async () => {
let response=await app.httpRequest().get('/users').expect(200);
const users=response.body;
initialSize=users.length;
assert(Array.isArray(users));
});
it('should POST /users',async () => {
let response=await app.httpRequest()
.post('/users')
.set('Content-Type','application/x-www-form-urlencoded')
.set('Accept','application/json')
.send(querystring.stringify(newUser))
.expect(200);
const user=response.body.data;
newUser.id=user.id;
insertId=user.id;
assert(!isNaN(newUser.id));
})
it('should GET /users/:id',async () => {
let response=await app.httpRequest()
.get(`/users/${insertId}`)
.set('Accept','application/json')
.expect(200);
let user=response.body.data;
assert(_.isEqual(user.id,newUser.id));
assert(_.isEqual(user.username,newUser.username));
assert(_.isEqual(user.password,newUser.password));
})
it('should PUT /users/:id',async () => {
newUser.username='更新后的username';
let response=await app.httpRequest()
.put(`/users/${insertId}`)
.set('Content-Type','application/x-www-form-urlencoded')
.send(querystring.stringify(newUser))
.set('Accept','application/json')
.expect(200);
let user=response.body.data;
assert(_.isEqual(user.username,newUser.username));
})
it('should DELETE /users/:id',async () => {
let response=await app.httpRequest()
.delete(`/users/${insertId}`)
.set('Accept','application/json')
.expect(200);
let data=response.body.data;
assert(_.isEqual(data,'删除成功'));
})
});
1.10 test/app/service/users.test.js [#](#t101.10 test/app/service/users.test.js)
test/app/service/users.test.js
const _=require('lodash');
const uuid=require('uuid');
const { app,assert } = require('egg-mock/bootstrap');
describe('test/app/service/users.test.js',() => {
let username=uuid.v4();
let insertId;
let newUser={
username: username,
password: username,
email: `${username}@qq.com`,
phone: username,
gender: 1,
birthday:'2018-09-09',
address:'回龙观'
}
it('select', async () => {
const ctx = app.mockContext();
const result = await ctx.service.users.select();
assert(Array.isArray(result));
});
it('insert', async () => {
const ctx = app.mockContext();
const result=await ctx.service.users.insert(newUser);
insertId=result.insertId;
newUser.id=insertId;
assert(!isNaN(newUser.id));
});
it('get', async () => {
const ctx = app.mockContext();
const result = await ctx.service.users.get(insertId);
assert(result.username = newUser.username);
});
it('update',async () => {
newUser.username='更新后的username';
const ctx = app.mockContext();
const result = await ctx.service.users.update(newUser);
assert(result.username = newUser.username);
});
it('delete', async () => {
const ctx = app.mockContext();
const result=await ctx.service.users.delete(insertId);
assert(result.affectedRows===1);
});
});
2. 角色管理 [#](#t112. 角色管理)
2.1 app/controller/roles.js [#](#t122.1 app/controller/roles.js)
const RestfulController = require('./restful');
class RolesController extends RestfulController {
constructor(...args) {
super(...args);
this.model = 'roles';
}
}
module.exports = RolesController;
2.2 app/service/roles.js [#](#t132.2 app/service/roles.js)
app/service/roles.js
const ApiService = require('./restful');
// ctx,app,service,config,logger
class RolesService extends ApiService {
constructor(...args) {
super(...args);
this.model = 'roles';
}
}
module.exports = RolesService;
3 权限 [#](#t143 权限)
3.1 app/controller/restful.js [#](#t153.1 app/controller/restful.js)
const BaseController = require('./base');
// ctx,app,service,config,logger
class RestfulController extends BaseController {
constructor(...args) {
super(...args);
}
async index() {
//_page _limit x-total-count
let {
ctx,
app,
model,
logger,
service
} = this;
let {
page,
limit,
...where
} = ctx.query;
const list = await service[this.model].select({
where,
order: [
['create_time', 'desc'],
['id', 'desc']
],
limit,
offset: (page - 1) * limit
});
const total = await service[this.model].count(where);
ctx.set('x-total-count', total);
this.success({
list,
total
});
}
async create() {
let {
ctx,
app,
service
} = this;
let body = ctx.request.body;
let result = await service[this.model].insert(body);
const insertSuccess = result.affectedRows === 1;
if (insertSuccess > 0) {
this.success({
id: result.insertId
});
} else {
this.error('添加失败');
}
}
async show() {
let {
ctx,
app,
service
} = this;
let id = ctx.params.id;
let model = await service[this.model].get(id);
this.success(model);
}
async update() {
let {
ctx,
app,
service
} = this;
let id = ctx.params.id;
let body = ctx.request.body;
let result = await service[this.model].update(body);
const insertSuccess = result.affectedRows === 1;
if (insertSuccess > 0) {
let updated = await service[this.model].get(id);
this.success(updated);
} else {
this.error('更新失败');
}
}
async destroy() {
let {
ctx,
app,
service
} = this;
let id = ctx.params.id;
let result = await service[this.model].delete(parseInt(id));
const insertSuccess = result.affectedRows === 1;
if (insertSuccess > 0) {
this.success('删除成功');
} else {
this.error('删除失败');
}
}
async destroyMulti() {
let {
ctx,
app,
service
} = this;
let ids=ctx.request.body;
let result = await service[this.model].deleteMulti(ids);
const insertSuccess = result.affectedRows === 1;
if (insertSuccess > 0) {
this.success('删除成功');
} else {
this.error('删除失败');
}
}
}
module.exports = RestfulController;
3.2 app/controller/roles.js [#](#t163.2 app/controller/roles.js)
const RestfulController = require('./restful');
class RolesController extends RestfulController {
constructor(...args) {
super(...args);
this.model = 'roles';
}
async setPermissions() {
let {
ctx,
app,
service
} = this;
let body=ctx.request.body;
await service[this.model].setPermissions(body);
this.success('设置权限成功');
}
async assignUsers() {
let {
ctx,
app,
service
} = this;
let body=ctx.request.body;
await service[this.model].assignUsers(body);
this.success('设置用户成功');
}
async getResources() {
let {service}=this;
let resources = await service[this.model].getResources();
this.success(resources);
}
async getUsers() {
let {service}=this;
let users = await service[this.model].getUsers();
this.success(users);
}
}
module.exports = RolesController;
3.3 app/router.js [#](#t173.3 app/router.js)
module.exports = app => {
const { router, controller } = app;
router.get('/roles/getResources',controller.roles.getResources);
router.get('/roles/getUsers',controller.roles.getUsers);
router.resources('users','/users',controller.users);
router.resources('roles','/roles',controller.roles);
router.resources('userRole','/userRole',controller.userRole);
router.resources('resources','/resources',controller.resources);
router.resources('roleResource','/roleResource',controller.roleResource);
router.delete('/users',controller.users.destroyMulti);
router.post('/roles/setPermissions',controller.roles.setPermissions);
router.post('/roles/assignUsers',controller.roles.assignUsers);
/*
router.resources('articles','/articles',controller.articles);
router.resources('carousels','/carousels',controller.carousels);
router.resources('categories','/categories',controller.categories);
router.resources('config','/config',controller.config);
router.resources('links','/links',controller.links);
router.resources('navigations','/navigations',controller.navigations);
router.resources('resources','/resources',controller.resources);
*/
};
3.4 app/service/restful.js [#](#t183.4 app/service/restful.js)
const Service = require('egg').Service;
// ctx,app,service,config,logger
class ApiService extends Service {
constructor(...args) {
super(...args);
}
async select(options) {
return await this.app.mysql.select(this.model,options);
}
async count(where) {
let total=await this.app.mysql.count(this.model,where);
return total;
}
async get(id) {
return await this.app.mysql.get(this.model, { id });
}
async insert(entity) {
return await this.app.mysql.insert(this.model, entity);
}
async update(entity) {
return await this.app.mysql.update(this.model, entity);
}
async delete(id) {
return await this.app.mysql.delete(this.model, { id });
}
async deleteMulti(ids) {
return await this.app.mysql.query(`delete from users where ?? IN (?)`,['id',ids]);
}
}
module.exports = ApiService;
3.5 app/service/roles.js [#](#t193.5 app/service/roles.js)
const ApiService = require('./restful');
// ctx,app,service,config,logger
class RolesService extends ApiService {
constructor(...args) {
super(...args);
this.model = 'roles';
}
async select(options) {
let roles=await this.app.mysql.select(this.model,options);
for (let i=0;i<roles.length;i++){
let rows=await this.app.mysql.query(`select resource_id from role_resource where role_id=?`,[roles[i].id]);
roles[i].resourceIds=rows.map(item => item.resource_id);
rows=await this.app.mysql.query(`select user_id from user_role where role_id=?`,[roles[i].id]);
roles[i].users=rows.map(item=>item.user_id);
}
return roles;
}
async setPermissions({roleId,resourceIds}) {
await this.app.mysql.query(`delete from role_resource where role_id =?`,[roleId]);
for (let i=0;i<resourceIds.length;i++){
await this.app.mysql.query(`insert into role_resource(role_id,resource_id) values(?,?)`,[roleId,parseInt(resourceIds[i])]);
}
}
async assignUsers({roleId,userIds}) {
await this.app.mysql.query(`delete from user_role where role_id =?`,[roleId]);
for (let i=0;i<userIds.length;i++){
await this.app.mysql.query(`insert into user_role(role_id,user_id) values(?,?)`,[roleId,parseInt(userIds[i])]);
}
}
async getUsers() {
return await this.app.mysql.select('users');
}
async getResources() {
let resources = await this.app.mysql.select('resources');
let map={};
let top=[];
resources=resources.filter(resource => {
resource.children=[];
map[resource.id]=resource;
if (resource.parent_id == 0) {
top.push(resource);
} else {
return true;
}
});
resources.forEach(resource => {
let parentId=resource.parent_id;
map[parentId].children.push(resource);
});
return top;
}
}
module.exports = RolesService;
3. 验证码和跨域 [#](#t203. 验证码和跨域)
3.1 app/router.js [#](#t213.1 app/router.js)
app/router.js
router.get('/captcha',controller.common.captcha);
3.2 app/controller/common.js [#](#t223.2 app/controller/common.js)
app/controller/common.js
const RestfulController=require('./restful');
const svgCaptcha = require('svg-captcha');
class UsersController extends RestfulController {
constructor(...args) {
super(...args);
this.model = 'users';
}
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 = UsersController;
3.2 config/config.default.js [#](#t233.2 config/config.default.js)
config/config.default.js
exports.security = {
domainWhiteList: [ 'http://localhost:8000' ],
};
3.3 config/plugin.js [#](#t243.3 config/plugin.js)
config/plugin.js
// config/plugin.js
module.exports.passport = {
enable: true,
package: 'egg-passport',
};
module.exports.passportGithub = {
enable: true,
package: 'egg-passport-github',
};
exports.cors = {
enable: true,
package: 'egg-cors',
};
#
4.注册和登录4.1 app/router.js [#](#t264.1 app/router.js)
app/router.js
const {router,controller}=app;
const auth=app.middleware.auth({},app);
router.post('/login',controller.users.login);
router.post('/signup',controller.users.signup);
router.get('/roles/getResources',auth,controller.roles.getResources);
router.get('/roles/getUsers',auth,controller.roles.getUsers);
router.resources('users','/users',auth,controller.users);
router.resources('roles','/roles',auth,controller.roles);
router.resources('userRole','/userRole',auth,controller.userRole);
router.resources('resources','/resources',auth,controller.resources);
router.resources('roleResource','/roleResource',auth,controller.roleResource);
router.delete('/users',auth,controller.users.destroyMulti);
router.post('/roles/setPermissions',auth,controller.roles.setPermissions);
router.post('/roles/assignUsers',auth,controller.roles.assignUsers);
4.2 app/controller/common.js [#](#t274.2 app/controller/common.js)
app/controller/common.js
async captcha() {
let {ctx}=this;
var captcha=svgCaptcha.create({});
ctx.session.captcha=captcha.text;
console.log(ctx.session)
ctx.set('Content-Type','image/svg+xml');
ctx.body=captcha.data;
}
4.3 app/controller/users.js [#](#t284.3 app/controller/users.js)
app/controller/users.js
const RestfulController=require('./restful');
const svgCaptcha=require('svg-captcha');
const {sign}=require('jsonwebtoken');
class UsersController extends RestfulController {
constructor(...args) {
super(...args);
this.model = 'users';
}
async login() {
let {ctx,app}=this;
let body=ctx.request.body;
const result = await app.mysql.select('users',{
where: {username:body.username,password:body.password},
limit: 1,
offset:0
});
if (result&&result.length>0) {
let user=JSON.parse(JSON.stringify(result[0]));
this.success(sign(user,this.config.jwtSecret));
} else {
this.error('登录失败');
}
}
async signup() {
let {ctx,app}=this;
let body=ctx.request.body;
let captcha=body.captcha;
body.address=body.address.join('-');
delete body.confirm;
delete body.captcha;
delete body.prefix;
if (ctx.session.captcha && captcha.toLowerCase() == ctx.session.captcha.toLowerCase()) {
const result=await app.mysql.insert('users',body);
const insertSuccess = result.affectedRows === 1;
if (insertSuccess > 0) {
this.success({
id: result.insertId
});
} else {
this.error('添加失败');
}
} else{
this.error('验证码错误!');
}
}
}
module.exports = UsersController;
4.4 app/middleware/auth.js [#](#t294.4 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'
}
}
}
}
4.5 config/config.default.js [#](#t304.5 config/config.default.js)
config/config.default.js
config.security = {
csrf: false,
domainWhiteList: [ 'http://localhost:8000' ]
};
config.jwtSecret="zxmf";
config.cors = {
credentials: true
}
config.session= {
renew: false,
}
4.6 config/plugin.js [#](#t314.6 config/plugin.js)
config/plugin.js
exports.cors = {
enable: true,
package: 'egg-cors'
};
Gitalking ...
Be the first guy leaving a comment!