首次完整推送,
V:1.20240808.006
This commit is contained in:
@ -0,0 +1,59 @@
|
||||
const methodPermission = require('../config/permission')
|
||||
const {
|
||||
ERROR
|
||||
} = require('../common/error')
|
||||
|
||||
function isAccessAllowed (user, setting) {
|
||||
const {
|
||||
role: userRole = [],
|
||||
permission: userPermission = []
|
||||
} = user
|
||||
const {
|
||||
role: settingRole = [],
|
||||
permission: settingPermission = []
|
||||
} = setting
|
||||
if (userRole.includes('admin')) {
|
||||
return
|
||||
}
|
||||
if (
|
||||
settingRole.length > 0 &&
|
||||
settingRole.every(item => !userRole.includes(item))
|
||||
) {
|
||||
throw {
|
||||
errCode: ERROR.PERMISSION_ERROR
|
||||
}
|
||||
}
|
||||
if (
|
||||
settingPermission.length > 0 &&
|
||||
settingPermission.every(item => !userPermission.includes(item))
|
||||
) {
|
||||
throw {
|
||||
errCode: ERROR.PERMISSION_ERROR
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = async function () {
|
||||
const methodName = this.getMethodName()
|
||||
if (!(methodName in methodPermission)) {
|
||||
return
|
||||
}
|
||||
const {
|
||||
auth,
|
||||
role,
|
||||
permission
|
||||
} = methodPermission[methodName]
|
||||
if (auth || role || permission) {
|
||||
await this.middleware.auth()
|
||||
}
|
||||
if (role && role.length === 0) {
|
||||
throw new Error('[AccessControl]Empty role array is not supported')
|
||||
}
|
||||
if (permission && permission.length === 0) {
|
||||
throw new Error('[AccessControl]Empty permission array is not supported')
|
||||
}
|
||||
return isAccessAllowed(this.authInfo, {
|
||||
role,
|
||||
permission
|
||||
})
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
module.exports = async function () {
|
||||
if (this.authInfo) { // 多次执行auth时如果第一次成功后续不再执行
|
||||
return
|
||||
}
|
||||
const token = this.getUniversalUniIdToken()
|
||||
const payload = await this.uniIdCommon.checkToken(token)
|
||||
if (payload.errCode) {
|
||||
throw payload
|
||||
}
|
||||
this.authInfo = payload
|
||||
if (payload.token) {
|
||||
this.response.newToken = {
|
||||
token: payload.token,
|
||||
tokenExpired: payload.tokenExpired
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
auth: require('./auth'),
|
||||
uniIdLog: require('./uni-id-log'),
|
||||
validate: require('./validate'),
|
||||
accessControl: require('./access-control'),
|
||||
verifyRequestSign: require('./verify-request-sign'),
|
||||
...require('./rbac')
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
const {
|
||||
ERROR
|
||||
} = require('../common/error')
|
||||
|
||||
function hasRole (...roleList) {
|
||||
const userRole = this.authInfo.role || []
|
||||
if (userRole.includes('admin')) {
|
||||
return
|
||||
}
|
||||
const isMatch = roleList.every(roleItem => {
|
||||
return userRole.includes(roleItem)
|
||||
})
|
||||
if (!isMatch) {
|
||||
throw {
|
||||
errCode: ERROR.PERMISSION_ERROR
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function hasPermission (...permissionList) {
|
||||
const userRole = this.authInfo.role || []
|
||||
const userPermission = this.authInfo.permission || []
|
||||
if (userRole.includes('admin')) {
|
||||
return
|
||||
}
|
||||
const isMatch = permissionList.every(permissionItem => {
|
||||
return userPermission.includes(permissionItem)
|
||||
})
|
||||
if (!isMatch) {
|
||||
throw {
|
||||
errCode: ERROR.PERMISSION_ERROR
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
hasRole,
|
||||
hasPermission
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
const db = uniCloud.database()
|
||||
module.exports = async function ({
|
||||
data = {},
|
||||
success = true,
|
||||
type = 'login'
|
||||
} = {}) {
|
||||
const now = Date.now()
|
||||
const uniIdLogCollection = db.collection('uni-id-log')
|
||||
const requiredDataKeyList = ['user_id', 'username', 'email', 'mobile']
|
||||
const dataCopy = {}
|
||||
for (let i = 0; i < requiredDataKeyList.length; i++) {
|
||||
const key = requiredDataKeyList[i]
|
||||
if (key in data && typeof data[key] === 'string') {
|
||||
dataCopy[key] = data[key]
|
||||
}
|
||||
}
|
||||
const {
|
||||
appId,
|
||||
clientIP,
|
||||
deviceId,
|
||||
userAgent
|
||||
} = this.getUniversalClientInfo()
|
||||
const logData = {
|
||||
appid: appId,
|
||||
device_id: deviceId,
|
||||
ip: clientIP,
|
||||
type,
|
||||
ua: userAgent,
|
||||
create_date: now,
|
||||
...dataCopy
|
||||
}
|
||||
|
||||
if (success) {
|
||||
logData.state = 1
|
||||
} else {
|
||||
logData.state = 0
|
||||
}
|
||||
return uniIdLogCollection.add(logData)
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
module.exports = function (value = {}, schema = {}) {
|
||||
const validateRes = this.validator.validate(value, schema)
|
||||
if (validateRes) {
|
||||
delete validateRes.schemaKey
|
||||
throw validateRes
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
const crypto = require('crypto')
|
||||
const createConfig = require('uni-config-center')
|
||||
const { verifyHttpInfo } = require('uni-cloud-s2s')
|
||||
|
||||
const { ERROR } = require('../common/error')
|
||||
const s2sConfig = createConfig({
|
||||
pluginId: 'uni-cloud-s2s'
|
||||
})
|
||||
const needSignFunctions = new Set([
|
||||
'externalRegister',
|
||||
'externalLogin',
|
||||
'updateUserInfoByExternal'
|
||||
])
|
||||
|
||||
module.exports = function () {
|
||||
const methodName = this.getMethodName()
|
||||
const { source } = this.getUniversalClientInfo()
|
||||
|
||||
// 指定接口需要鉴权
|
||||
if (!needSignFunctions.has(methodName)) return
|
||||
|
||||
// 非 HTTP 方式请求拒绝访问
|
||||
if (source !== 'http') {
|
||||
throw {
|
||||
errCode: ERROR.ILLEGAL_REQUEST
|
||||
}
|
||||
}
|
||||
|
||||
// 支持 uni-cloud-s2s 验证请求
|
||||
if (s2sConfig.hasFile('config.json')) {
|
||||
try {
|
||||
if (!verifyHttpInfo(this.getHttpInfo())) {
|
||||
throw {
|
||||
errCode: ERROR.ILLEGAL_REQUEST
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
if (e.errSubject === 'uni-cloud-s2s') {
|
||||
throw {
|
||||
errCode: ERROR.ILLEGAL_REQUEST,
|
||||
errMsg: e.errMsg
|
||||
}
|
||||
}
|
||||
throw e
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.config.requestAuthSecret || typeof this.config.requestAuthSecret !== 'string') {
|
||||
throw {
|
||||
errCode: ERROR.CONFIG_FIELD_REQUIRED,
|
||||
errMsgValue: {
|
||||
field: 'requestAuthSecret'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const timeout = 20 * 1000 // 请求超过20秒不能再请求,防止重放攻击
|
||||
const { headers, body: _body } = this.getHttpInfo()
|
||||
const { 'uni-id-nonce': nonce, 'uni-id-timestamp': timestamp, 'uni-id-signature': signature } = headers
|
||||
const body = JSON.parse(_body).params || {}
|
||||
const bodyStr = Object.keys(body)
|
||||
.sort()
|
||||
.filter(item => typeof body[item] !== 'object')
|
||||
.map(item => `${item}=${body[item]}`)
|
||||
.join('&')
|
||||
|
||||
if (isNaN(Number(timestamp)) || (Number(timestamp) + timeout) < Date.now()) {
|
||||
console.error('[timestamp error], timestamp:', timestamp, 'timeout:', timeout)
|
||||
|
||||
throw {
|
||||
errCode: ERROR.ILLEGAL_REQUEST
|
||||
}
|
||||
}
|
||||
|
||||
const reSignature = crypto.createHmac('sha256', `${this.config.requestAuthSecret + nonce}`).update(`${timestamp}${bodyStr}`).digest('hex')
|
||||
|
||||
if (signature !== reSignature.toUpperCase()) {
|
||||
console.error('[signature error], signature:', signature, 'reSignature:', reSignature.toUpperCase(), 'requestAuthSecret:', this.config.requestAuthSecret)
|
||||
throw {
|
||||
errCode: ERROR.ILLEGAL_REQUEST
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user