Browse Source

Merge branch 'dev_trial' of https://gitea.free-sun.vip/free-sun/FS-IOT into dev_trial

release_0.0.1
deartibers 3 years ago
parent
commit
a45a0a9a50
  1. 11
      code/VideoAccess-VCMP/api/.vscode/launch.json
  2. 189
      code/VideoAccess-VCMP/api/app/lib/controllers/auth/index.js
  3. 68
      code/VideoAccess-VCMP/api/app/lib/controllers/nvr/index.js
  4. 5
      code/VideoAccess-VCMP/api/app/lib/index.js
  5. 25
      code/VideoAccess-VCMP/api/app/lib/middlewares/authenticator.js
  6. 32
      code/VideoAccess-VCMP/api/app/lib/routes/auth/index.js
  7. 11
      code/VideoAccess-VCMP/api/app/lib/routes/nvr/index.js
  8. 29
      code/VideoAccess-VCMP/api/app/lib/service/redis.js
  9. 14
      code/VideoAccess-VCMP/api/config.js
  10. 4
      code/VideoAccess-VCMP/api/package.json

11
code/VideoAccess-VCMP/api/.vscode/launch.json

@ -13,12 +13,11 @@
"NODE_ENV": "development"
},
"args": [
"-p 14000",
"-f http://localhost:14000",
// "-g postgres://postgres:123@10.8.30.32:5432/yinjiguanli",
// "-g postgres://postgres:123456@221.230.55.27:5432/yinjiguanli",
// "-g postgres://FashionAdmin:123456@10.8.30.156:5432/SmartEmergency",
"-g postgres://postgres:Mantis1921@116.63.50.139:54327/smartYingji"
"-p 4000",
"-f http://localhost:4000",
"-g postgres://postgres:123@10.8.30.32:5432/video_access",
"--redisHost 127.0.0.1",
"--redisPort 6379"
]
},
{

189
code/VideoAccess-VCMP/api/app/lib/controllers/auth/index.js

@ -1,189 +0,0 @@
'use strict';
const Hex = require('crypto-js/enc-hex');
const MD5 = require('crypto-js/md5');
const moment = require('moment');
const uuid = require('uuid');
async function login(ctx, next) {
const transaction = await ctx.fs.dc.orm.transaction();
try {
const models = ctx.fs.dc.models;
const params = ctx.request.body;
let password = Hex.stringify(MD5(params.password));
const userRes = await models.User.findOne({
where: {
username: params.username,
password: password,
delete: false,
},
attributes: { exclude: ['password'] },
include: [{
attributes: ["resourceId"],
model: models.UserResource
}]
});
if (!userRes) {
ctx.status = 400;
ctx.body = {
"message": "账号或密码错误"
}
} else if (!userRes.enable) {
ctx.status = 400;
ctx.body = { message: "该用户已被禁用" }
} else {
const token = uuid.v4();
let userRslt = Object.assign(userRes.dataValues, {
authorized: true,
token: token,
userResources: userRes.userResources.map(r => r.resourceId),
});
await models.UserToken.create({
token: token,
userInfo: userRslt,
expired: moment().add(30, 'days').format()
});
ctx.status = 200;
ctx.body = userRslt;
}
await transaction.commit();
} catch (error) {
await transaction.rollback();
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
"message": "登录失败"
}
}
}
/**
* 微信小程序登录
* @@requires.body {phone-手机号, password-密码} ctx
*/
async function wxLogin(ctx, next) {
const transaction = await ctx.fs.dc.orm.transaction();
try {
const models = ctx.fs.dc.models;
const params = ctx.request.body;
let password = Hex.stringify(MD5(params.password));
const userRes = await models.User.findOne({
where: {
phone: params.phone,
password: password,
delete: false,
},
attributes: { exclude: ['password'] }
});
if (!userRes) {
ctx.status = 400;
ctx.body = { message: "手机号或密码错误" }
} else if (!userRes.enable) {
ctx.status = 400;
ctx.body = { message: "该用户已被禁用" }
} else {
const token = uuid.v4();
//获取用户关注区域信息
const departmentRes = await models.Department.findOne({ where: { id: userRes.departmentId } });
let attentionRegion = departmentRes;
while (attentionRegion.dependence && attentionRegion.type != 1) {
const departmentParent = await models.Department.findOne({ where: { id: attentionRegion.dependence } });
attentionRegion = {
...departmentParent.dataValues,
nextRegin: attentionRegion
}
}
//获取用户权限信息
const resourceRes = await models.UserResource.findAll({
where: {
userId: userRes.id
},
include: [{
model: models.Resource,
attributes: ['code', 'name'],
}],
attributes: []
});
let userRslt = Object.assign({
authorized: true,
token: token,
...userRes.dataValues
});
await models.UserToken.create({
token: token,
userInfo: userRslt,
expired: moment().add(30, 'day').format('YYYY-MM-DD HH:mm:ss')
}, { transaction: transaction });
ctx.status = 200;
ctx.body = Object.assign({
...userRslt,
userRegionType: departmentRes.type,//1-市级,2-区县级,3-乡镇级,4-村级
attentionRegion: attentionRegion,
resources: resourceRes.map(r => r.resource)
});
}
await transaction.commit();
} catch (error) {
await transaction.rollback();
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
"message": "登录失败"
}
}
}
async function logout(ctx) {
try {
const { token, code } = ctx.request.body;
const models = ctx.fs.dc.models;
await models.UserToken.destroy({
where: {
token: token,
},
});
ctx.status = 204;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
"message": "登出失败"
}
}
}
/**
* 微信小程序登出
* @request.body {token-用户登录Token} ctx
*/
async function wxLogout(ctx) {
try {
const { token } = ctx.request.body;
const models = ctx.fs.dc.models;
await models.UserToken.destroy({
where: {
token: token,
},
});
ctx.status = 204;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
"message": "登出失败"
}
}
}
module.exports = {
login,
wxLogin,
logout,
wxLogout
};

68
code/VideoAccess-VCMP/api/app/lib/controllers/nvr/index.js

@ -0,0 +1,68 @@
'use strict';
const moment = require('moment')
async function edit (ctx, next) {
const transaction = await ctx.fs.dc.orm.transaction();
try {
const models = ctx.fs.dc.models;
const { userId } = ctx.fs.api
const data = ctx.request.body;
// 或取其他服务信息
const nvrData = {
channelCount: 8,
port: 8080,
}
if (data.id) {
// 修改
const storageData = Object.assign({}, data, nvrData)
await models.Nvr.update(storageData, {
where: {
id: data.id
},
transaction
})
} else {
// 添加
const storageData = Object.assign({}, data, nvrData, {
createTime: moment().format(),
createUserId: userId,
delete: false,
})
await models.Nvr.create(storageData, { transaction })
}
await transaction.commit();
ctx.status = 204;
} catch (error) {
await transaction.rollback();
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {}
}
}
async function del (ctx, next) {
try {
const models = ctx.fs.dc.models;
const { nvrId } = ctx.params
await models.Nvr.destroy({
where: {
id: nvrId
}
})
ctx.status = 204;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {}
}
}
module.exports = {
edit,
del,
};

5
code/VideoAccess-VCMP/api/app/lib/index.js

@ -1,6 +1,7 @@
'use strict';
const routes = require('./routes');
const redisConnect = require('./service/redis')
const authenticator = require('./middlewares/authenticator');
// const apiLog = require('./middlewares/api-log');
const businessRest = require('./middlewares/business-rest');
@ -12,8 +13,10 @@ module.exports.entry = function (app, router, opts) {
app.fs.api.authAttr = app.fs.api.authAttr || {};
app.fs.api.logAttr = app.fs.api.logAttr || {};
redisConnect(app, opts)
router.use(authenticator(app, opts));
router.use(businessRest(app, router, opts));
// router.use(businessRest(app, router, opts));
// router.use(apiLog(app, opts));
router = routes(app, router, opts);

25
code/VideoAccess-VCMP/api/app/lib/middlewares/authenticator.js

@ -13,13 +13,13 @@ class ExcludesUrls {
this.reload(opts);
}
sanitizePath(path) {
sanitizePath (path) {
if (!path) return '/';
const p = '/' + path.replace(/^\/+/i, '').replace(/\/+$/, '').replace(/\/{2,}/, '/');
return p;
}
reload(opts) {
reload (opts) {
// load all url
if (!this.allUrls) {
this.allUrls = opts;
@ -37,7 +37,7 @@ class ExcludesUrls {
}
}
isExcluded(path, method) {
isExcluded (path, method) {
return this.allUrls.some(function (url) {
return !url.auth
&& url.pregexp.test(path)
@ -58,9 +58,7 @@ let isPathExcluded = function (opts, path, method) {
if (!excludeAll) {
let excludeOpts = opts.exclude || [];
excludeOpts.push({ p: '/login', o: 'POST' });
excludeOpts.push({ p: '/wxLogin', o: 'POST' });
excludeOpts.push({ p: '/logout', o: 'PUT' });
excludeOpts.push({ p: '/wxLogout', o: 'PUT' });
excludes = new ExcludesUrls(excludeOpts);
}
let excluded = excludeAll || excludes.isExcluded(path, method);
@ -72,14 +70,10 @@ let authorizeToken = async function (ctx, token) {
const tokenFormatRegexp = /^(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})$/g;
if (token && tokenFormatRegexp.test(token)) {
try {
const axyRes = await ctx.fs.dc.models.UserToken.findOne({
where: {
token: token,
expired: { $gte: moment().format('YYYY-MM-DD HH:mm:ss') }
}
});
const { userInfo, expired } = axyRes;
if (!expired || moment().valueOf() <= moment(expired).valueOf()) {
const expired = await ctx.redis.hget(token, 'expired');
if (expired && moment().valueOf() <= moment(expired).valueOf()) {
const userInfo = JSON.parse(await ctx.redis.hget(token, 'userInfo'));
rslt = {
'authorized': userInfo.authorized,
'resources': (userInfo || {}).resources || [],
@ -112,13 +106,14 @@ let isResourceAvailable = function (resources, options) {
return !authCode || (resources || []).some(code => code === authCode);
};
function factory(app, opts) {
return async function auth(ctx, next) {
function factory (app, opts) {
return async function auth (ctx, next) {
const { path, method, header, query } = ctx;
ctx.fs.logger.log('[AUTH] start', path, method);
ctx.fs.api = ctx.fs.api || {};
ctx.fs.port = opts.port;
ctx.redis = app.redis;
ctx.redisTools = app.redisTools;
let error = null;
if (path) {
if (!isPathExcluded(opts, path, method)) {

32
code/VideoAccess-VCMP/api/app/lib/routes/auth/index.js

@ -1,32 +0,0 @@
'use strict';
const auth = require('../../controllers/auth');
module.exports = function (app, router, opts) {
/**
* @api {Post} login 登录.
* @apiVersion 1.0.0
* @apiGroup Auth
*/
app.fs.api.logAttr['POST/login'] = { content: '登录', visible: true };
router.post('/login', auth.login);
/**
* @api {POST} wxLogin 微信小程序登录.使用手机号密码登录
* @apiVersion 1.0.0
* @apiGroup Auth
*/
app.fs.api.logAttr['POST/wxLogin'] = { content: '微信小程序登录', visible: true };
router.post('/wxLogin', auth.wxLogin);
app.fs.api.logAttr['PUT/logout'] = { content: '登出', visible: false };
router.put('/logout', auth.logout);
/**
* @api {PUT} wxLogout 微信小程序登出
* @apiVersion 1.0.0
* @apiGroup Auth
*/
app.fs.api.logAttr['PUT/wxLogout'] = { content: '登出', visible: false };
router.put('/wxLogout', auth.wxLogout);
};

11
code/VideoAccess-VCMP/api/app/lib/routes/nvr/index.js

@ -0,0 +1,11 @@
'use strict';
const nvr = require('../../controllers/nvr');
module.exports = function (app, router, opts) {
app.fs.api.logAttr['POST/nvr'] = { content: '添加/修改nvr', visible: false };
router.post('/nvr', nvr.edit);
app.fs.api.logAttr['DEL/nvr'] = { content: '删除nvr', visible: false };
router.del('/nvr/:nvrId', nvr.del);
};

29
code/VideoAccess-VCMP/api/app/lib/service/redis.js

@ -0,0 +1,29 @@
'use strict';
const redis = require("ioredis")
const moment = require('moment')
module.exports = async function factory (app, opts) {
let client = new redis(opts.redis.port, opts.redis.host);
client.on("error", function (err) {
app.fs.logger.error('info', '[FS-AUTH-REDIS]', 'redis connect error.');
console.error("Error :", err);
process.exit(-1);
});
client.on('connect', function () {
console.log(`redis connect success ${opts.redis.host + ':' + opts.redis.port}`);
})
// 自定义方法
async function hdelall (key) {
const obj = await client.hgetall(key);
const hkeys = Object.keys(obj)
await client.hdel(key, hkeys)
}
app.redis = client
app.redisTools = {
hdelall,
}
}

14
code/VideoAccess-VCMP/api/config.js

@ -11,13 +11,20 @@ const dev = process.env.NODE_ENV == 'development';
args.option(['p', 'port'], '启动端口');
args.option(['g', 'pg'], 'postgre服务URL');
args.option(['f', 'fileHost'], '文件中心本地化存储: WebApi 服务器地址(必填), 该服务器提供文件上传Web服务');
args.option('redisHost', 'redisHost');
args.option('redisPort', 'redisPort');
args.option('redisPswd', 'redisPassword');
const flags = args.parse(process.argv);
const IOT_VIDEO_ACCESS_DB = process.env.IOT_VIDEO_ACCESS_DB || flags.pg;
const IOT_VIDEO_ACCESS_LOCAL_SVR_ORIGIN = process.env.IOT_VIDEO_ACCESS_LOCAL_SVR_ORIGIN || flags.fileHost;
if (!IOT_VIDEO_ACCESS_DB) {
const IOTA_REDIS_SERVER_HOST = process.env.IOTA_REDIS_SERVER_HOST || flags.redisHost || "localhost";//redis IP
const IOTA_REDIS_SERVER_PORT = process.env.IOTA_REDIS_SERVER_PORT || flags.redisPort || "6379";//redis 端口
const IOTA_REDIS_SERVER_PWD = process.env.IOTA_REDIS_SERVER_PWD || flags.redisPswd || "";//redis 密码
if (!IOT_VIDEO_ACCESS_DB || !IOTA_REDIS_SERVER_HOST || !IOTA_REDIS_SERVER_PORT) {
console.log('缺少启动参数,异常退出');
args.showHelp();
process.exit(-1);
@ -41,6 +48,11 @@ const product = {
entry: require('./app').entry,
opts: {
exclude: [], // 不做认证的路由,也可以使用 exclude: ["*"] 跳过所有路由
redis: {
host: IOTA_REDIS_SERVER_HOST,
port: IOTA_REDIS_SERVER_PORT,
pwd: IOTA_REDIS_SERVER_PWD
},
}
}
],

4
code/VideoAccess-VCMP/api/package.json

@ -5,7 +5,7 @@
"main": "server.js",
"scripts": {
"test": "set DEBUG=true&&\"node_modules/.bin/mocha\" --harmony --reporter spec app/test/*.test.js",
"start": "set NODE_ENV=development&&node server -p 14000 -g postgres://postgres:123@10.8.30.32:5432/yinjiguanli -f http://localhost:14000",
"start": "set NODE_ENV=development&&node server -p 4000 -g postgres://postgres:123@10.8.30.32:5432/video_access -f http://localhost:4000",
"start:linux": "export NODE_ENV=development&&node server -p 4000 -g postgres://FashionAdmin:123456@10.8.30.39:5432/pm1",
"automate": "sequelize-automate -c sequelize-automate.config.js"
},
@ -18,7 +18,7 @@
"crypto-js": "^4.0.0",
"file-saver": "^2.0.2",
"fs-web-server-scaffold": "^2.0.2",
"ioredis": "^4.19.4",
"ioredis": "^5.0.4",
"koa-convert": "^1.2.0",
"koa-proxy": "^0.9.0",
"moment": "^2.24.0",

Loading…
Cancel
Save