91 lines
4.7 KiB
Plaintext
91 lines
4.7 KiB
Plaintext
import { requestJson } from '@/services/api.uts'
|
|||
|
|
import { acceptSession } from './auth.uts'
|
||
|
|
|
||
|
|
export function wechatLoginSupported(): boolean {
|
||
|
|
// App微信SDK及各平台应用凭据接入后再开放原生入口。
|
||
|
|
// #ifdef MP-WEIXIN
|
||
|
|
return true
|
||
|
|
// #endif
|
||
|
|
// #ifndef MP-WEIXIN
|
||
|
|
return false
|
||
|
|
// #endif
|
||
|
|
}
|
||
|
|
|
||
|
|
export function requestWechatAuthorization(): Promise<string> {
|
||
|
|
// #ifdef MP-WEIXIN
|
||
|
|
return new Promise<string>((resolve, reject) => {
|
||
|
|
uni.login({
|
||
|
|
provider: 'weixin',
|
||
|
|
success: (result) => {
|
||
|
|
const code = result.code
|
||
|
|
if (code.length == 0) { reject(new Error('未能取得微信登录凭证,请重新操作')); return }
|
||
|
|
resolve(code)
|
||
|
|
},
|
||
|
|
fail: (error) => {
|
||
|
|
const cancelled = error.errMsg.toLowerCase().includes('cancel') || error.errCode == 1310509
|
||
|
|
reject(new Error(cancelled ? '已取消微信登录' : '微信授权失败,请重新操作'))
|
||
|
|
}
|
||
|
|
})
|
||
|
|
})
|
||
|
|
// #endif
|
||
|
|
// #ifndef MP-WEIXIN
|
||
|
|
return new Promise<string>((resolve, reject) => {
|
||
|
|
reject(new Error('当前平台暂未开放微信登录,请使用手机号登录'))
|
||
|
|
})
|
||
|
|
// #endif
|
||
|
|
}
|
||
|
|
|
||
|
|
function validTicket(value: string): boolean { return /^[A-Za-z0-9_-]{32,128}$/.test(value) }
|
||
|
|
function validPhone(value: string): boolean { return /^1[3-9][0-9]{9}$/.test(value) }
|
||
|
|
|
||
|
|
function validateResult(result: UTSJSONObject): UTSJSONObject {
|
||
|
|
const status = result.getString('status') ?? ''
|
||
|
|
if (status == 'bind_required') {
|
||
|
|
const expires = result.getNumber('expiresIn') ?? 0
|
||
|
|
if (!validTicket(result.getString('bindingTicket') ?? '') || expires < 1 || expires > 600 || Math.floor(expires) != expires || result['token'] != null)
|
||
|
|
throw new Error('微信绑定响应格式不完整,请重新微信登录')
|
||
|
|
} else if (status == 'authenticated') {
|
||
|
|
const expiry = Date.parse(result.getString('expiresAt') ?? '')
|
||
|
|
if (result.getBoolean('consentsConfirmed') != true || !validPhone(result.getString('phone') ?? '')
|
||
|
|
|| !/^[1-9][0-9]{0,18}$/.test(result.getString('userId') ?? '') || (result.getString('token') ?? '').length == 0
|
||
|
|
|| isNaN(expiry) || expiry <= Date.now()) throw new Error('微信登录响应缺少有效账户或协议确认')
|
||
|
|
} else throw new Error('微信登录响应状态无效')
|
||
|
|
return result
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function requestWechatLogin(code: string, agreements: UTSJSONObject[]): Promise<UTSJSONObject> {
|
||
|
|
if (code.length == 0 || code.length > 256 || agreements.length != 2) throw new Error('请重新确认协议并微信登录')
|
||
|
|
let terms = false; let privacy = false; let previousRequestId = ''
|
||
|
|
for (const item of agreements) {
|
||
|
|
const agreementCode = item['agreementCode'] as string | null ?? ''
|
||
|
|
const requestId = item['requestId'] as string | null ?? ''
|
||
|
|
if ((agreementCode == 'terms' && !terms)) terms = true
|
||
|
|
else if ((agreementCode == 'privacy' && !privacy)) privacy = true
|
||
|
|
else throw new Error('用户协议和隐私政策必须分别确认')
|
||
|
|
if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(item['agreementVersion'] as string | null ?? '')
|
||
|
|
|| !/^[a-f0-9]{64}$/.test(item['contentHash'] as string | null ?? '') || !/^[A-Za-z0-9_-]{16,64}$/.test(requestId)
|
||
|
|
|| requestId == previousRequestId) throw new Error('协议确认信息不完整,请重新阅读并确认')
|
||
|
|
previousRequestId = requestId
|
||
|
|
}
|
||
|
|
return validateResult(await requestJson('/auth/wechat-login', 'POST', { platform: 'mp-weixin', code, agreements }))
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function requestWechatBindingCode(bindingTicket: string, phone: string): Promise<boolean> {
|
||
|
|
if (!validTicket(bindingTicket) || !validPhone(phone)) throw new Error('请重新微信登录并输入正确手机号')
|
||
|
|
await requestJson('/auth/wechat/sms-code', 'POST', { bindingTicket, phone })
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function bindWechatPhone(bindingTicket: string, phone: string, code: string): Promise<UTSJSONObject> {
|
||
|
|
if (!validTicket(bindingTicket) || !validPhone(phone) || !/^[0-9]{6}$/.test(code)) throw new Error('请核对手机号和6位验证码')
|
||
|
|
const result = validateResult(await requestJson('/auth/wechat/bind-phone', 'POST', { bindingTicket, phone, code }))
|
||
|
|
if (result.getString('status') != 'authenticated') throw new Error('手机号绑定尚未完成,请重新微信登录')
|
||
|
|
return result
|
||
|
|
}
|
||
|
|
|
||
|
|
export function acceptWechatSession(result: UTSJSONObject): string {
|
||
|
|
validateResult(result)
|
||
|
|
if (result.getString('status') != 'authenticated') throw new Error('请先完成手机号绑定')
|
||
|
|
return acceptSession(result, result.getString('phone') ?? '')
|
||
|
|
}
|