'use strict'; // ! OAUTH2.0 模式 const uuid = require('uuid'); const moment = require('moment'); // 暂时定制予 vcmp 视频平台 app async function apply (ctx) { try { const { models } = ctx.fs.dc; const { body } = ctx.request; const { authorization } = ctx.headers; const { utils: { oauthParseAuthHeader, oauthParseBody } } = ctx.app.fs await oauthParseBody(body, 'apply'); const keySplit = await oauthParseAuthHeader(authorization); // TODO 删除此应用下的其他 token // 记录token const userInfo = { appKey: keySplit[0], appSecret: keySplit[1] } const token = uuid.v4(); const expired = moment().add(1, 'year'); await models.UserToken.create({ token: token, userInfo: userInfo, expired: expired.format('YYYY-MM-DD HH:mm:ss') }); ctx.status = 200; ctx.body = { token: token, expires: expired.toISOString() }; } catch (e) { ctx.status = 400; ctx.body = { name: 'RequestError', message: e.message }; } } async function refresh (ctx) { const transaction = await ctx.fs.dc.orm.transaction(); try { const { authorization } = ctx.headers; const { body } = ctx.request; const { models } = ctx.fs.dc; const { utils: { oauthParseAuthHeader, oauthParseBody } } = ctx.app.fs const keySplit = await oauthParseAuthHeader(authorization); const $token = await oauthParseBody(body, 'refresh'); const oldToken = await models.UserToken.findOne({ where: { token: $token, expired: { $gte: moment().format('YYYY-MM-DD HH:mm:ss') } } }); if ( !oldToken || oldToken.userInfo.appKey != keySplit[0] || oldToken.userInfo.appSecret != keySplit[1] ) { throw new Error('参数无效:正文token无效或已过期,请重新申请'); } const token = uuid.v4(); const expired = moment().add(1, 'year'); // 记录token const tokenMsg = { token: token, userInfo: oldToken.userInfo, expired: expired.format('YYYY-MM-DD HH:mm:ss') } await models.UserToken.create(tokenMsg, { transaction }); await ctx.redis.hmset(token, tokenMsg); // 移除旧的token await models.UserToken.destroy({ where: { token: $token }, transaction }); await ctx.redisTools.hdelall($token); await transaction.commit(); ctx.status = 200; ctx.body = { token: token, expires: expired.toISOString() }; } catch (e) { await transaction.rollback(); ctx.status = 400; ctx.body = { name: 'RequestError', message: e.message }; } } async function invalidate (ctx) { const transaction = await ctx.fs.dc.orm.transaction(); try { const { models } = ctx.fs.dc; const { body } = ctx.request; const { authorization } = ctx.headers; const { utils: { oauthParseAuthHeader, oauthParseBody } } = ctx.app.fs const keySplit = await oauthParseAuthHeader(authorization); const $token = await oauthParseBody(body, 'invalidate'); // 删除token await models.UserToken.destroy({ where: { token: $token } }); await ctx.redisTools.hdelall($token); await transaction.commit(); ctx.status = 204; } catch (e) { await transaction.rollback(); ctx.status = 400; ctx.body = { name: 'RequestError', message: e.message }; } } async function invalidateAll (ctx) { // 给其他系统删除token const transaction = await ctx.fs.dc.orm.transaction(); try { const { models } = ctx.fs.dc; const { appKey } = ctx.query; const tokenRes = await models.UserToken.findAll({ where: { 'userInfo.appKey': appKey } }) // 删除token await models.UserToken.destroy({ where: { 'userInfo.appKey': appKey }, transaction }); tokenRes.forEach(async t => { await ctx.redisTools.hdelall(t.token); }) await transaction.commit(); ctx.status = 204; } catch (e) { await transaction.rollback(); ctx.status = 400; ctx.body = { name: 'RequestError', message: e.message }; } } // OAUTH2.0 END module.exports = { apply, refresh, invalidate, invalidateAll, // 给其他系统删除token }