This commit is contained in:
Jay 2021-09-01 21:15:26 +08:00
parent 2e05f90851
commit 94837efdee
6 changed files with 51 additions and 45 deletions

View File

@ -36,5 +36,5 @@ controller.logout = () => async (ctx) => {
}
controller.getInfo = () => async (ctx) => {
ctx.resp(resp.Success, {})
ctx.resp(resp.Success, ctx.token.info)
}

View File

@ -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
}

View File

@ -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)

View File

@ -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())

10
utils/acl.js Normal file
View File

@ -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
}

View File

@ -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 = {