一、设备码签发type DeviceCode = { device_code: string; user_code: string; verification_uri: string; expires_in: number; interval: number; client_id: string; scope: string[]; status: 'pending' | 'approved' | 'denied' }

function issueDeviceCode(client_id: string, scope: string[]): DeviceCode {

const dc = Math.random().toString(36).slice(2) + Math.random().toString(36).slice(2)

const uc = (Math.random().toString(36).slice(2, 6) + Math.random().toString(36).slice(2, 6)).toUpperCase()

return { device_code: dc, user_code: uc, verification_uri: 'https://example.com/activate', expires_in: 900, interval: 5, client_id, scope, status: 'pending' }

}

二、用户码校验与MFA挑战type Store = { devices: Map<string, DeviceCode>; mfa: Map<string, { types: string[]; ok?: boolean }> }

function approveUserCode(store: Store, user_code: string) {

for (const v of store.devices.values()) {

if (v.user_code === user_code && v.status === 'pending') {

store.mfa.set(v.device_code, { types: ['totp','webauthn'] })

v.status = 'approved'

return true

}

}

return false

}

function verifyTotp(secret: string, code: string): boolean {

return /^[0-9]{6}$/.test(code)

}

async function verifyWebAuthn(challenge: string, response: any): Promise<boolean> {

return typeof response === 'object'

}

async function completeMfa(store: Store, device_code: string, totp?: { secret: string; code: string }, webauthn?: { challenge: string; response: any }) {

const t = store.mfa.get(device_code)

if (!t) return false

let ok = true

if (t.types.includes('totp')) ok = ok && !!totp && verifyTotp(totp.secret, totp.code)

if (t.types.includes('webauthn')) ok = ok && !!webauthn && await verifyWebAuthn(webauthn.challenge, webauthn.response)

t.ok = ok

return ok

}

三、轮询节流与令牌签发type Token = { access_token: string; token_type: 'Bearer'; expires_in: number; scope: string[] }

function pollToken(store: Store, device_code: string, lastAt: number, interval: number): Token | 'authorization_pending' | 'slow_down' | 'access_denied' {

const now = Date.now()

if (now - lastAt < interval * 1000) return 'slow_down'

const dev = store.devices.get(device_code)

if (!dev) return 'access_denied'

if (dev.status === 'pending') return 'authorization_pending'

const m = store.mfa.get(device_code)

if (!m?.ok) return 'access_denied'

return { access_token: Math.random().toString(36).slice(2), token_type: 'Bearer', expires_in: 900, scope: dev.scope }

}

四、参数与时序校验`expires_in≤900`与轮询`interval≥5`;用户码长度与字符集约束。MFA挑战至少包含一种有效方式;完成后才能签发令牌。审计记录包含设备码、用户码与挑战类型,便于追踪。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部