mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-10 02:30:46 +08:00
change log in
This commit is contained in:
parent
9cf026f605
commit
8ca42dd973
211 changed files with 48417 additions and 109 deletions
94
uds-auth/lib/middleware/auth-middleware.js
Normal file
94
uds-auth/lib/middleware/auth-middleware.js
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
import { UdsClient } from '../uds/client.js'
|
||||
import { UdsValidator } from '../uds/validator.js'
|
||||
import { ROLES, computePermissions } from '../roles.js'
|
||||
|
||||
/**
|
||||
* auth-middleware: 从 PORTALSSOUser (empNo) 取用户,注入 role/permissions
|
||||
*
|
||||
* 三条路径:
|
||||
* 1. 有 empNo + 有 session → 续期,注入
|
||||
* 2. 有 empNo + 无 session → 创建 session + bootstrap role
|
||||
* 3. 无 empNo → 未登录,交给下游
|
||||
*/
|
||||
export function createAuthMiddleware(config, sessionStore, rolesStore) {
|
||||
const udsClient = new UdsClient(config.udsAuth)
|
||||
const validatorConfig = {
|
||||
...config.udsAuth,
|
||||
authMode: config.udsAuth?.authMode || 'trust',
|
||||
}
|
||||
const udsValidator = new UdsValidator(validatorConfig)
|
||||
const { cookieMaxAge, slidingExpiration, slidingInterval } = config.session
|
||||
|
||||
function extractEmpNo(cookieHeader) {
|
||||
// 优先取 UDS 的 empNo,其次取 fallback administrator
|
||||
const udsMatch = cookieHeader?.match(/(?:PORTALSSOUser|ZTEDPGSSOUser)=([^;]+)/)
|
||||
if (udsMatch) return decodeURIComponent(udsMatch[1].trim())
|
||||
const fbMatch = cookieHeader?.match(/UDS_FALLBACK_USER=([^;]+)/)
|
||||
if (fbMatch) return decodeURIComponent(fbMatch[1].trim())
|
||||
return null
|
||||
}
|
||||
|
||||
async function authMiddleware(ctx, next) {
|
||||
const { req } = ctx
|
||||
const cookieHeader = req.headers.cookie || ''
|
||||
const empNo = extractEmpNo(cookieHeader)
|
||||
|
||||
if (!empNo) return next()
|
||||
|
||||
// 1. 有 session → 续期
|
||||
let userContext = await sessionStore.get(empNo)
|
||||
if (userContext) {
|
||||
if (slidingExpiration && userContext.lastActiveAt) {
|
||||
const lastActive = new Date(userContext.lastActiveAt).getTime()
|
||||
if (Date.now() - lastActive >= slidingInterval) {
|
||||
userContext.lastActiveAt = new Date().toISOString()
|
||||
await sessionStore.setex(empNo, Math.floor(cookieMaxAge / 1000), userContext)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 2. 无 session → 创建
|
||||
// 信任模式下,empNo 来自我们自己的 QR 登录流程设置的 cookie,
|
||||
// 即使没有完整的 header 凭据也应建立会话。
|
||||
const credentials = udsValidator.extractCredentials(req)
|
||||
if (udsValidator.authMode === 'trust') {
|
||||
// trust 模式:只要有 empNo 就建立会话;token 可选
|
||||
userContext = udsValidator.buildUserContext(
|
||||
credentials || { empNo, token: '', lang: 'zh-CN' },
|
||||
false,
|
||||
)
|
||||
} else {
|
||||
// verify 模式:必须有有效凭据
|
||||
if (!credentials || !udsValidator.validateCredentials(credentials)) {
|
||||
return next()
|
||||
}
|
||||
userContext = udsValidator.buildUserContext(credentials, false)
|
||||
}
|
||||
userContext.authenticatedAt = new Date().toISOString()
|
||||
userContext.lastActiveAt = new Date().toISOString()
|
||||
userContext.isAuthenticated = true
|
||||
await sessionStore.setex(empNo, Math.floor(cookieMaxAge / 1000), userContext)
|
||||
}
|
||||
|
||||
// 注入 role + permissions
|
||||
const role = rolesStore.getRole(empNo)
|
||||
ctx.userContext = userContext
|
||||
ctx.empNo = empNo
|
||||
ctx.role = role
|
||||
ctx.permissions = computePermissions(role)
|
||||
return next()
|
||||
}
|
||||
|
||||
authMiddleware.udsClient = udsClient
|
||||
authMiddleware.udsValidator = udsValidator
|
||||
return authMiddleware
|
||||
}
|
||||
|
||||
/**
|
||||
* 权限守卫 — 拦截非 super_admin 的管理 API
|
||||
* 用法: 在路由里 call guard(req, res, ctx, 'canManageUsers') → true 表示通过
|
||||
*/
|
||||
export function requirePermission(ctx, permission) {
|
||||
if (!ctx?.permissions) return false
|
||||
if (permission === 'super_admin') return ctx.role === ROLES.SUPER_ADMIN || ctx.role === ROLES.FALLBACK_ADMIN
|
||||
return !!ctx.permissions[permission]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue