diff --git a/package.json b/package.json index 65aae58..26942aa 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "fs-extra": "^8.0.0", "glob": "^7.1.4", "helmet": "^3.18.0", + "jsonwebtoken": "^8.5.1", "ldapjs": "^1.0.2", "method-override": "^3.0.0", "mongoose": "^5.5.7", diff --git a/src/bin/express.js b/src/bin/express.js index deb62b7..0edce13 100644 --- a/src/bin/express.js +++ b/src/bin/express.js @@ -172,11 +172,13 @@ app.use(function(err, req, res, next) { if (req.path.startsWith('/api')) { res.json({ errcode: 10, errmsg: err.message }); } else { - res.render('error', { - message: err.status === 404 ? err.message : '服务器君开小差啦 @(・●・)@', - error: err, - title: err.status - }); + + // TODO: + // res.render('error', { + // message: err.status === 404 ? err.message : '服务器君开小差啦 @(・●・)@', + // error: err, + // title: err.status + // }); } }); diff --git a/src/controllers/common/index.js b/src/controllers/common/index.js index 7ced2c2..fa89d36 100644 --- a/src/controllers/common/index.js +++ b/src/controllers/common/index.js @@ -1,11 +1,12 @@ -import {Router} from 'express'; +import { Router } from 'express'; + +import testCtrl from './test'; const router = new Router(); -router.get('/test', async(req, res, next) => { - res.send({ - msg: 'test!' - }) -}) +// TODO: +router.get('/test', testCtrl); -export default router; \ No newline at end of file + + +export default router; diff --git a/src/controllers/common/test.js b/src/controllers/common/test.js new file mode 100644 index 0000000..43bf9f2 --- /dev/null +++ b/src/controllers/common/test.js @@ -0,0 +1,37 @@ +import { User, Role } from './../../models/admin/User'; + +export default function(req, res, next) { + // const newRole = new Role({ + // rolename: 'normal', + // permissions: ['game-readable', 'sys-writable'] + // }); + + // newRole.save(function(err, role) { + // console.log(role); + // }); + + // res.send({ + // res: 'ok' + // }) + +// let normalid; +// Role.findOne({ rolename: 'normal' }).then(data => { +// normalid = data._id; +// console.log(normalid); + +// User.updateOne( +// { +// username: 'yulixing' +// }, +// {$pull: {permissions: null}} +// ).exec() +// }); + + +User.findOne({username: "yulixing"}).populate({path: 'permissions'}).exec((err, res) => { + console.log(res) + console.log(res.permissions) +}) + + res.send({}); +} diff --git a/src/controllers/sys/index.js b/src/controllers/sys/index.js new file mode 100644 index 0000000..49d6788 --- /dev/null +++ b/src/controllers/sys/index.js @@ -0,0 +1,11 @@ +import { Router } from 'express'; +import userListCtrl from './user-list'; + + + +const router = new Router(); + +router.get('/user-list', userListCtrl); + + +export default router; diff --git a/src/controllers/sys/user-list.js b/src/controllers/sys/user-list.js new file mode 100644 index 0000000..8c57238 --- /dev/null +++ b/src/controllers/sys/user-list.js @@ -0,0 +1,73 @@ +import ldap from 'ldapjs'; +import config from '../../../config/config'; +import { User, LdapUser } from '../../models/admin/User'; + +export default function(req, res, next) { + const client = ldap.createClient({ + url: config.ldap.url + }); + const opts = { + filter: '(&(objectClass=posixAccount)(o=gmplatform))', + scope: 'sub', + timeLimit: 500 + }; + const data = []; + + client.bind(config.ldap.user, config.ldap.pwd, function(err, bindRes) { + if (err) next(err); + client.search('ou=people,dc=kingsome,dc=cn', opts, function( + err, + searchRes + ) { + if (err) next(err); + searchRes.on('searchEntry', function(entry) { + data.push(entry.object); + }); + searchRes.on('error', function(err) { + client.unbind(); + next(err); + }); + searchRes.on('end', async function(result) { + try { + let users = data; + users = users.map(user => { + user.userinfo = user.uidNumber; + return user; + }); + + const delResult = await LdapUser.remove({}); + const saveResult = await LdapUser.insertMany(data); + + // 取出完整用户信息 + // 首次查询 + let compUserList = await LdapUser.find({}).populate({ + path: 'userinfo' + }); + + compUserList.map(async user => { + if (!user.userinfo) { + const newUser = new User({ + _id: user.uidNumber, + username: user.uid, + fullname: user.sn + }); + await newUser.save(); + } + }); + + // 再次查询 + compUserList = await LdapUser.find({}).populate({ + path: 'userinfo' + }); + + res.send({ + res: compUserList + }); + client.unbind(); + } catch (err) { + next(err); + } + }); + }); + }); +} diff --git a/src/controllers/users/index.js b/src/controllers/users/index.js new file mode 100644 index 0000000..cc07b0c --- /dev/null +++ b/src/controllers/users/index.js @@ -0,0 +1,12 @@ +import { Router } from 'express'; +import loginCtrl from './login'; +import userInfoCtrl from './user-info'; + + +const router = new Router(); + +router.post('/login', loginCtrl); +router.get('/user-info', userInfoCtrl); + + +export default router; diff --git a/src/controllers/users/login.js b/src/controllers/users/login.js new file mode 100644 index 0000000..86676de --- /dev/null +++ b/src/controllers/users/login.js @@ -0,0 +1,90 @@ +import ldap from 'ldapjs'; +import jwt from 'jsonwebtoken'; +import config from '../../../config/config'; +import {User} from '../../models/admin/User'; + +export default function(req, res, next) { + const body = req.body; + const client = ldap.createClient({ + url: config.ldap.url + }); + const opts = { + filter: `(uid=${body.username})`, + scope: 'sub', + timeLimit: 500 + }; + const data = []; + + client.bind(config.ldap.user, config.ldap.pwd, function(err, bindRes) { + if (err) next(err); + client.search('ou=people,dc=kingsome,dc=cn', opts, function( + err, + searchRes + ) { + if (err) next(err); + searchRes.on('searchEntry', function(entry) { + data.push(entry.object); + }); + searchRes.on('error', function(err) { + client.unbind(); + next(err); + }); + searchRes.on('end', function(result) { + if (data.length > 0) { + // 用户存在,验证密码 + const user = data[0]; + const dn = user.dn; + client.bind('cn=虞丽星,ou=people,dc=kingsome,dc=cn', 'yulixing123456', async function(err, verifyRes) { + // client.bind(dn, body.pwd, async function(err, verifyRes) { + // 登录成功 + if (err === null) { + const token = jwt.sign( + { + username: user.uid + }, + config.jwtSecret, + { + expiresIn: 60 * 60 * 2 + } + ); + + try { + let userSearch = await User.findOne({ username: user.uid }); + if (!userSearch) { + const newUser = new User({ + _id:user.uidNumber, + username: user.uid, + fullname: user.sn, + }); + const saveResult = await newUser.save(); + console.log(saveResult) + userSearch = saveResult; + } + res.send({ + errcode: 0, + token, + userInfo: userSearch + }); + } catch (err) { + next(err); + } + } else { + console.log(err) + res.send({ + errcode: 1, + errmsg: '密码不正确。' + }); + } + }); + } else { + // 用户不存在 + res.send({ + errcode: 2, + errmsg: '用户不存在。' + }); + } + client.unbind(); + }); + }); + }); +} diff --git a/src/controllers/users/user-info.js b/src/controllers/users/user-info.js new file mode 100644 index 0000000..60e12af --- /dev/null +++ b/src/controllers/users/user-info.js @@ -0,0 +1,75 @@ +import jwt from 'jsonwebtoken'; +import config from '../../../config/config'; +import { User } from '../../models/admin/User'; + +export default function(req, res, next) { + const BearerToken = req.headers.authorization; + console.log(BearerToken); + if (!BearerToken) { + // 无权限 + res.send({ + errcode: 1, + errmsg: '用户无权限。' + }); + } else { + const token = getToken(BearerToken); + if (!token) { + // 异常 + res.send({ + errcode: 1, + errmsg: 'token 异常。' + }); + } else { + jwt.verify(token, config.jwtSecret, async (err, decode) => { + if (err) { + // 验证不通过 + res.send({ + errcode: 1, + errmsg: err.message + }); + } else { + // 验证通过 + // 获取用户信息 + try { + const username = decode.username; + const searchResult = await User.findOne({ username }).populate({ + path: 'permissions' + }).exec(); + console.log(searchResult); + if (!searchResult) { + res.send({ + errcode: 1, + errmsg: '用户信息发生异常。' + }); + } else { + let permissions = [...searchResult.permissions]; + permissions = permissions.map(permission => { + return permission.permissions; + }); + permissions = permissions.reduce((pre, cur) => { + return pre.concat([...cur]); + }, []); + + const userInfo = JSON.parse(JSON.stringify(searchResult)); + userInfo.permits = permissions; + + + res.send({ + errcode: 0, + userInfo + }); + } + } catch (err) { + next(err); + } + } + }); + } + } +} + +function getToken(str) { + const reg = /^Bearer (.+)/; + const result = reg.exec(str); + return result ? result[1] : ''; +} diff --git a/src/models/admin/User.js b/src/models/admin/User.js new file mode 100644 index 0000000..468b2d2 --- /dev/null +++ b/src/models/admin/User.js @@ -0,0 +1,74 @@ +'use strict'; +import mongoose from 'mongoose'; + +/** + * 用户信息 + */ +const UserSchema = new mongoose.Schema( + { + // uidNumber + _id: { type: String, required: true }, + // 用户名 + username: { type: String }, + // 姓名 + fullname: { type: String }, + // 头像 + avatar: { + type: String, + default: + 'https://hbimg.huabanimg.com/dd46766769229284b75a0142d239c3f7a5f4a2bf37ead-9XoIGZ_fw658' + }, + // 角色 + roles: [{ type: String }], + // 权限组 + permissions: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Role' }], + // 状态 + status: { type: String, default: '0' }, + // 签名 + signature: { type: String }, + // 备注 + comment: { type: String }, + // 更改人 + lastModifiedBy: { type: String } + }, + { + collection: 'users', + timestamps: true + } +); + +/* 角色权限 */ + +const RoleSchema = new mongoose.Schema( + { + // 角色名 + rolename: { type: String }, + // 权限 + permissions: [{ type: String }] + }, + { + collection: 'roles', + timestamps: true + } +); + +/* Ldap 用户 */ + +const LdapUserSchema = new mongoose.Schema( + { + cn: { type: String }, + uid: { type: String }, + uidNumber: { type: String }, + userinfo: { type: String, ref: 'User' } + }, + { + collection: 'ldap-users', + timestamps: true + } +); + +const User = mongoose.model('User', UserSchema); +const Role = mongoose.model('Role', RoleSchema); +const LdapUser = mongoose.model('LdapUser', LdapUserSchema); + +export { User, Role, LdapUser }; diff --git a/src/router/index.js b/src/router/index.js index 6ba59cb..c8308c0 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -2,10 +2,14 @@ import {Router} from 'express'; import commonRouter from './../controllers/common' +import sysRouter from './../controllers/sys' +import usersRouter from './../controllers/users' const router = new Router(); router.use('/common', commonRouter); +router.use('/sys', sysRouter); +router.use('/users', usersRouter); export default router \ No newline at end of file diff --git a/test/test2.js b/test/test2.js index d7f1a40..e84bfe3 100644 --- a/test/test2.js +++ b/test/test2.js @@ -50,7 +50,6 @@ app.get('/', function(req, res, next) { //查询结束 res2.on('end', function(result) { - console.log('search status: ' + result); console.log(entries) if (entries.length !== 0) { client.bind(entries[0].dn, 'yulixing123456', function( diff --git a/test/test3.js b/test/test3.js new file mode 100644 index 0000000..8f91ea9 --- /dev/null +++ b/test/test3.js @@ -0,0 +1,7 @@ +import {Role} from './../src/models/admin/User' + + +const newRole = new Role({ + rolename: 'normal', + permissions: ['game-readable', 'sys-writable'] +}) \ No newline at end of file