修复打手短信验证码发送
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
import { createRequire } from 'node:module'
|
||||
|
||||
import { runtimeConfig } from '../../config/runtime.js'
|
||||
import { createHttpError } from '../../utils/http.js'
|
||||
import { logWarn } from '../../utils/logger.js'
|
||||
|
||||
const require = createRequire(import.meta.url)
|
||||
const Dysmsapi = require('@alicloud/dysmsapi20170525') as {
|
||||
default: new (config: unknown) => AliyunSmsClient
|
||||
SendSmsRequest: new (input: Record<string, unknown>) => unknown
|
||||
}
|
||||
const OpenApiClient = require('@alicloud/openapi-client') as {
|
||||
Config: new (config: Record<string, unknown>) => unknown
|
||||
}
|
||||
|
||||
type AliyunSmsClient = {
|
||||
sendSmsWithOptions(
|
||||
request: unknown,
|
||||
runtime: unknown,
|
||||
): Promise<{ body?: { code?: string; message?: string } }>
|
||||
}
|
||||
|
||||
export interface SmsProvider {
|
||||
sendCode(phone: string, code: string): Promise<void>
|
||||
}
|
||||
|
||||
const ALIYUN_DEFAULT_ENDPOINT = 'dysmsapi.aliyuncs.com'
|
||||
|
||||
export function getSmsProvider(): SmsProvider {
|
||||
const config = runtimeConfig.worker.sms
|
||||
if (String(config.provider || '').trim() === 'aliyun') {
|
||||
const accessKeyId = String(config.accessKeyId || '').trim()
|
||||
const accessKeySecret = String(config.accessKeySecret || '').trim()
|
||||
const signName = String(config.signName || '').trim()
|
||||
const templateCode = String(config.templateCode || '').trim()
|
||||
if (!accessKeyId || !accessKeySecret || !signName || !templateCode) {
|
||||
logWarn('[sms]', '阿里云短信配置不完整,已降级为 Mock 模式', {
|
||||
hasAccessKeyId: Boolean(accessKeyId),
|
||||
hasAccessKeySecret: Boolean(accessKeySecret),
|
||||
hasSignName: Boolean(signName),
|
||||
hasTemplateCode: Boolean(templateCode),
|
||||
})
|
||||
return new MockSmsProvider()
|
||||
}
|
||||
return new AliyunSmsProvider({ accessKeyId, accessKeySecret, signName, templateCode })
|
||||
}
|
||||
return new MockSmsProvider()
|
||||
}
|
||||
|
||||
export class MockSmsProvider implements SmsProvider {
|
||||
async sendCode(phone: string, code: string) {
|
||||
logWarn('[sms/mock]', `【开发模式】手机验证码:${phone} → ${code}`, {
|
||||
phone,
|
||||
code,
|
||||
hint: '生产环境请配置 WORKER_SMS_PROVIDER=aliyun 后使用真实短信',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export class AliyunSmsProvider implements SmsProvider {
|
||||
private readonly client: AliyunSmsClient
|
||||
private readonly signName: string
|
||||
private readonly templateCode: string
|
||||
|
||||
constructor(input: {
|
||||
accessKeyId: string
|
||||
accessKeySecret: string
|
||||
signName: string
|
||||
templateCode: string
|
||||
endpoint?: string
|
||||
}) {
|
||||
const Config = OpenApiClient.Config
|
||||
this.client = new Dysmsapi.default(
|
||||
new Config({
|
||||
accessKeyId: input.accessKeyId,
|
||||
accessKeySecret: input.accessKeySecret,
|
||||
endpoint: (input.endpoint || ALIYUN_DEFAULT_ENDPOINT).replace(/^https?:\/\//, ''),
|
||||
}),
|
||||
) as AliyunSmsClient
|
||||
this.signName = input.signName
|
||||
this.templateCode = input.templateCode
|
||||
}
|
||||
|
||||
async sendCode(phone: string, code: string) {
|
||||
try {
|
||||
const request = new Dysmsapi.SendSmsRequest({
|
||||
phoneNumbers: phone,
|
||||
signName: this.signName,
|
||||
templateCode: this.templateCode,
|
||||
templateParam: JSON.stringify({ code }),
|
||||
})
|
||||
const response = await this.client.sendSmsWithOptions(request, {})
|
||||
const resultCode = String(response?.body?.code || '')
|
||||
if (resultCode !== 'OK') {
|
||||
throw createHttpError(
|
||||
`短信发送失败:${String(response?.body?.message || resultCode || '未知错误').trim()}`,
|
||||
{
|
||||
statusCode: 502,
|
||||
errorCode: 'worker_sms_send_failed',
|
||||
},
|
||||
)
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof Error && 'errorCode' in error) {
|
||||
throw error
|
||||
}
|
||||
throw createHttpError(
|
||||
`短信发送失败:${error instanceof Error ? error.message : '未知错误'}`,
|
||||
{
|
||||
statusCode: 502,
|
||||
errorCode: 'worker_sms_send_failed',
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user