Skip to content
Auth

发送短信钩子

Use your own SMS service to send authentication messages.

发送短信 Hook 替代了 Supabase 内置的短信发送功能。你可以使用这个 Hook 来:

🌐 The Send SMS Hook replaces Supabase's built-in SMS sending. You can use this hook to:

  • 使用本地短信服务提供商
  • 使用像 WhatsApp 这样的备用消息渠道
  • 如果你的主要服务提供商失败,就换另一个吧
  • 调整消息正文以包含特定平台的字段,例如 AppHash

输入

字段类型描述
userUser尝试登录的用户。
smsobject与发送短信过程相关的元数据。包括一次性密码(OTP)。
1
{
2
"user": {
3
"id": "6481a5c1-3d37-4a56-9f6a-bee08c554965",
4
"aud": "authenticated",
5
"role": "authenticated",
6
"email": "",
7
"phone": "+1333363128",
8
"phone_confirmed_at": "2024-05-13T11:52:48.157306Z",
9
"confirmation_sent_at": "2024-05-14T12:31:52.824573Z",
10
"confirmed_at": "2024-05-13T11:52:48.157306Z",
11
"phone_change_sent_at": "2024-05-13T11:47:02.183064Z",
12
"last_sign_in_at": "2024-05-13T11:52:48.162518Z",
13
"app_metadata": {
14
"provider": "phone",
15
"providers": ["phone"]
16
},
17
"user_metadata": {},
18
"identities": [
19
{
20
"identity_id": "3be5e552-65aa-41d9-9db9-2a502f845459",
21
"id": "6481a5c1-3d37-4a56-9f6a-bee08c554965",
22
"user_id": "6481a5c1-3d37-4a56-9f6a-bee08c554965",
23
"identity_data": {
24
"email_verified": false,
25
"phone": "+1612341244428",
26
"phone_verified": true,
27
"sub": "6481a5c1-3d37-4a56-9f6a-bee08c554965"
28
},
29
"provider": "phone",
30
"last_sign_in_at": "2024-05-13T11:52:48.155562Z",
31
"created_at": "2024-05-13T11:52:48.155599Z",
32
"updated_at": "2024-05-13T11:52:48.159391Z"
33
}
34
],
35
"created_at": "2024-05-13T11:45:33.7738Z",
36
"updated_at": "2024-05-14T12:31:52.82475Z",
37
"is_anonymous": false
38
},
39
"sms": {
40
"otp": "561166"
41
}
42
}

输出

  • 不需要输出。空响应且状态码为200被视为成功响应。

你们公司使用一个工作人员来管理所有与消息相关的工作。出于性能考虑,消息系统通过作业队列按间隔发送消息。消息不会立即发送,而是被排入队列,然后通过 pg_cron 按周期发送。

🌐 Your company uses a worker to manage all messaging related jobs. For performance reasons, the messaging system sends messages in intervals via a job queue. Instead of sending a message immediately, messages are queued and sent in periodic intervals via pg_cron.

创建一个用于存储工作的表

🌐 Create a table to store jobs

1
create table job_queue (
2
job_id uuid primary key default gen_random_uuid(),
3
job_data jsonb not null,
4
created_at timestamp default now(),
5
status text default 'pending',
6
priority int default 0,
7
retry_count int default 0,
8
max_retries int default 2,
9
scheduled_at timestamp default now()
10
);

创建钩子:

🌐 Create the hook:

1
create or replace function send_sms(event jsonb) returns void as $$
2
declare
3
job_data jsonb;
4
scheduled_time timestamp;
5
priority int;
6
begin
7
-- extract phone and otp from the event json
8
job_data := jsonb_build_object(
9
'phone', event->'user'->>'phone',
10
'otp', event->'sms'->>'otp'
11
);
12
13
-- calculate the nearest 5-minute window for scheduled_time
14
scheduled_time := date_trunc('minute', now()) + interval '5 minute' * floor(extract('epoch' from (now() - date_trunc('minute', now())) / 60) / 5);
15
16
-- assign priority dynamically (example logic: higher priority for earlier scheduled time)
17
priority := extract('epoch' from (scheduled_time - now()))::int;
18
19
-- insert the job into the job_queue table
20
insert into job_queue (job_data, priority, scheduled_at, max_retries)
21
values (job_data, priority, scheduled_time, 2);
22
end;
23
$$ language plpgsql;
24
25
grant all
26
on table public.job_queue
27
to supabase_auth_admin;
28
29
revoke all
30
on table public.job_queue
31
from authenticated, anon;

创建一个函数,定期运行并清空所有任务队列

🌐 Create a function to periodically run and dequeue all jobs

1
create or replace function dequeue_and_run_jobs() returns void as $$
2
declare
3
job record;
4
begin
5
for job in
6
select * from job_queue
7
where status = 'pending'
8
and scheduled_at <= now()
9
order by priority desc, created_at
10
for update skip locked
11
loop
12
begin
13
-- add job processing logic here.
14
-- for demonstration, we'll just update the job status to 'completed'.
15
update job_queue
16
set status = 'completed'
17
where job_id = job.job_id;
18
19
exception when others then
20
-- handle job failure and retry logic
21
if job.retry_count < job.max_retries then
22
update job_queue
23
set retry_count = retry_count + 1,
24
scheduled_at = now() + interval '1 minute' -- delay retry by 1 minute
25
where job_id = job.job_id;
26
else
27
update job_queue
28
set status = 'failed'
29
where job_id = job.job_id;
30
end if;
31
end;
32
end loop;
33
end;
34
$$ language plpgsql;
35
36
grant execute
37
on function public.dequeue_and_run_jobs
38
to supabase_auth_admin;
39
40
revoke execute
41
on function public.dequeue_and_run_jobs
42
from authenticated, anon;

配置 pg_cron 以在间隔时间运行任务。你可以使用像 crontab.guru 这样的工具来检查你的任务是否按合适的时间表运行。确保在 Database > Extensions 下启用 pg_cron

🌐 Configure pg_cron to run the job on an interval. You can use a tool like crontab.guru to check that your job is running on an appropriate schedule. Ensure that pg_cron is enabled under Database > Extensions

1
select
2
cron.schedule(
3
'* * * * *', -- this cron expression means every minute.
4
'select dequeue_and_run_jobs();'
5
);