diff --git a/controllers/account/index.js b/controllers/account/index.js index 03a69de..705048e 100644 --- a/controllers/account/index.js +++ b/controllers/account/index.js @@ -36,5 +36,5 @@ controller.logout = () => async (ctx) => { } controller.getInfo = () => async (ctx) => { - ctx.resp(resp.Success, {}) + ctx.resp(resp.Success, ctx.token.info) } diff --git a/controllers/common/index.js b/controllers/common/index.js index a9e0d4d..07de1c2 100644 --- a/controllers/common/index.js +++ b/controllers/common/index.js @@ -5,7 +5,9 @@ const joi = require('joi') const response = require('src/utils/response/index.js') const config = require('src/config/index.js') const { jwt } = require('src/utils/pkgs.js') -const { copyObject, toNumber } = require('src/utils/index.js') +const sso = require('src/utils/sso/index.js') +const { copyObject } = require('src/utils/index.js') +const { get: getCacheInstance } = require('src/utils/cache.js') const { Success, InternalError, DataFormat, Forbidden, Unauthorized } = response.resp @@ -107,7 +109,7 @@ controller.validate = schema => { * @param {boolean=} allowExpired * @return {import('koa').Middleware} */ -controller.authorization = allowExpired => { +controller.authorization = () => { return async (ctx, next) => { ctx.token = {} /** @type {string} */ @@ -122,44 +124,40 @@ controller.authorization = allowExpired => { [, ctx.token.origin] = strs - let decoded = {} - let expired = false + const decoded = {} try { - decoded = jwt.verify(strs[1], config.server.jwt_secret) + // 可以考慮這邊做個cache 多久之內存取不會到keycloak驗證 + let userInfo = await sso.getUserInfo(ctx.token.origin) + if (!userInfo) { + // try refresh + const cache = getCacheInstance() + const refreshToken = cache.get(ctx.token.origin) + if (!refreshToken) throw new Error('no cache data') + const token = await sso.refreshToken(refreshToken) + // set new cache + cache.set(token.access_token, token.refresh_token, false) + ctx.token.origin = token.access_token + userInfo = await sso.getUserInfo(token.access_token) + if (!userInfo) throw new Error('get user info fail') - await joi - .object({ - user_id: joi.string().required() - }) - .unknown() - .validateAsync(decoded) - } catch (err) { - debug(`jwt token verify fail: ${util.inspect(err, false, null)}`) - if (err instanceof jwt.TokenExpiredError) { - decoded = jwt.decode(ctx.token.origin) - expired = true - } else { - throw err + ctx.set('x-new-token', ctx.token.origin) } + + Object.assign(decoded, userInfo) + } catch (err) { + debug(`user info get fail ::: ${util.inspect(err, false, null)}`) + ctx.err(Unauthorized) } - ctx.token.user_id = decoded.user_id - ctx.token.sso = !!decoded.sso + ctx.token.user_id = decoded.username + ctx.token.sso = true - if (expired) ctx.err(Forbidden, response.codeMessage.CodeTokenExpired) + ctx.token.info = decoded ctx.verified = true } catch (err) { debug(`Token valid fail: ${util.inspect(err, false, null)}`) - if (err instanceof response.APIError) { - // 如果是過期的錯誤,判斷是否允許過期存取 - // @ts-ignore - // eslint-disable-next-line - if (err._object?.object?.code === response.codeMessage.CodeTokenExpired.code) { - if (allowExpired) return next() - } - } throw err } diff --git a/controllers/oauth/index.js b/controllers/oauth/index.js index 0361b56..42012fb 100644 --- a/controllers/oauth/index.js +++ b/controllers/oauth/index.js @@ -3,9 +3,10 @@ const util = require('util') const url = require('url') const sso = require('src/utils/sso/index.js') const { get: getCacheInstance } = require('src/utils/cache.js') -const { codeMessage, APIError } = require('src/utils/response/index.js') +const { resp, codeMessage, APIError } = require('src/utils/response/index.js') const config = require('src/config/index.js') -const { jwt } = require('src/utils/pkgs.js') +const acl = require('src/utils/acl.js') +const { copyObject } = require('src/utils/index.js') const controller = {} module.exports = controller @@ -34,6 +35,12 @@ controller.verifyCode = () => async (ctx) => { try { const token = await sso.getToken(code, sessionState) + if (!acl.checkAllow(token.groups)) { + const copy = copyObject(resp.Forbidden) + copy.object = codeMessage.CodeAccountNoPermission + throw new APIError('account no permission', copy) + } + // set accessToken/refreshToken cache cache.set(token.access_token, token.refresh_token, false) diff --git a/routes/api/index.js b/routes/api/index.js index df6d0f4..a0ee186 100644 --- a/routes/api/index.js +++ b/routes/api/index.js @@ -27,16 +27,6 @@ r.get( accCtrl.loginSSO() ) -/** - * account refresh token - * @swagger - * @route POST /api/refresh - * @group account - account apis - * @security JWT - * @returns {RespDefault.model} default - - */ -r.post('/refresh', commonCtrl.authorization(true), accCtrl.logout()) - /** * account logout * @swagger @@ -45,7 +35,7 @@ r.post('/refresh', commonCtrl.authorization(true), accCtrl.logout()) * @security JWT * @returns {RespDefault.model} default - */ -r.post('/logout', commonCtrl.authorization(false), accCtrl.logout()) +r.post('/logout', commonCtrl.authorization(), accCtrl.logout()) /** * account get info @@ -55,4 +45,4 @@ r.post('/logout', commonCtrl.authorization(false), accCtrl.logout()) * @security JWT * @returns {RespDefault.model} default - */ -r.get('/userinfo', commonCtrl.authorization(false), accCtrl.getInfo()) +r.get('/userinfo', commonCtrl.authorization(), accCtrl.getInfo()) diff --git a/utils/acl.js b/utils/acl.js new file mode 100644 index 0000000..6ba5b57 --- /dev/null +++ b/utils/acl.js @@ -0,0 +1,10 @@ +const ALLOW_GROUPS = new Set(['/professorx']) + +const mod = {} +module.exports = mod + +mod.checkAllow = groups => { + if (!Array.isArray(groups)) return false + + return groups.filter(t => ALLOW_GROUPS.has(t)).length > 0 +} diff --git a/utils/response/index.js b/utils/response/index.js index 098d1c7..61d9c66 100644 --- a/utils/response/index.js +++ b/utils/response/index.js @@ -57,7 +57,8 @@ mod.codeMessage = { CodeUnauthorized: { code: 1004, message: 'unauthorized' }, CodeForbidden: { code: 1005, message: 'forbidden' }, CodeNotFound: { code: 1006, message: 'not found' }, - CodeInternalError: { code: 1007, message: 'internal error' } + CodeInternalError: { code: 1007, message: 'internal error' }, + CodeAccountNoPermission: { code: 1008, message: 'account no permission' } } mod.resp = {