Skip to content
Auth

多因素认证验证钩子

你可以通过钩子给 Supabase 多因素认证实现 添加额外的检查。例如,你可以:

🌐 You can add additional checks to the Supabase MFA implementation with hooks. For example, you can:

  • 限制在一段时间内进行的验证尝试次数。
  • 登出那些验证尝试太多次失败的用户。
  • 统计、限速或禁止登录。

输入

Supabase Auth 会向你的 hook 发送包含这些字段的负载:

🌐 Supabase Auth will send a payload containing these fields to your hook:

字段类型描述
factor_idstring正在验证的多因素认证因素的唯一标识符
factor_typestringtotpphone
user_idstring用户的唯一标识符
validboolean验证尝试是否有效。对于 TOTP,这意味着六位数代码正确(true)或错误(false)。
1
{
2
"factor_id": "6eab6a69-7766-48bf-95d8-bd8f606894db",
3
"user_id": "3919cb6e-4215-4478-a960-6d3454326cec",
4
"valid": true
5
}

输出

如果你的钩子没有错误地处理输入,就返回这个。

🌐 Return this if your hook processed the input without errors.

字段类型描述
decisionstring关于是否允许认证继续的决定。使用 reject 拒绝验证尝试,并将用户从所有活跃会话中注销。使用 continue 来使用默认的 Supabase Auth 行为。
messagestring如果决定是 reject,显示给用户的消息。
1
{
2
"decision": "reject",
3
"message": "You have exceeded maximum number of MFA attempts."
4
}

你们公司要求用户输入错误的多因素验证代码,每次间隔不得少于2秒。

🌐 Your company requires that a user can input an incorrect MFA Verification code no more than once every 2 seconds.

创建一个表格来记录用户最后一次多因素认证错误尝试的时间。

🌐 Create a table to record the last time a user had an incorrect MFA verification attempt for a factor.

1
create table public.mfa_failed_verification_attempts (
2
user_id uuid not null,
3
factor_id uuid not null,
4
last_failed_at timestamp not null default now(),
5
primary key (user_id, factor_id)
6
);

创建一个钩子来读取和写入这个表的信息。例如:

🌐 Create a hook to read and write information to this table. For example:

1
create function public.hook_mfa_verification_attempt(event jsonb)
2
returns jsonb
3
language plpgsql
4
as $$
5
declare
6
last_failed_at timestamp;
7
begin
8
if event->'valid' is true then
9
-- code is valid, accept it
10
return jsonb_build_object('decision', 'continue');
11
end if;
12
13
select last_failed_at into last_failed_at
14
from public.mfa_failed_verification_attempts
15
where
16
user_id = event->'user_id'
17
and
18
factor_id = event->'factor_id';
19
20
if last_failed_at is not null and now() - last_failed_at < interval '2 seconds' then
21
-- last attempt was done too quickly
22
return jsonb_build_object(
23
'error', jsonb_build_object(
24
'http_code', 429,
25
'message', 'Please wait a moment before trying again.'
26
)
27
);
28
end if;
29
30
-- record this failed attempt
31
insert into public.mfa_failed_verification_attempts
32
(
33
user_id,
34
factor_id,
35
last_failed_at
36
)
37
values
38
(
39
event->'user_id',
40
event->'factor_id',
41
now()
42
)
43
on conflict do update
44
set last_failed_at = now();
45
46
-- finally let Supabase Auth do the default behavior for a failed attempt
47
return jsonb_build_object('decision', 'continue');
48
end;
49
$$;
50
51
-- Assign appropriate permissions and revoke access
52
grant all
53
on table public.mfa_failed_verification_attempts
54
to supabase_auth_admin;
55
56
revoke all
57
on table public.mfa_failed_verification_attempts
58
from authenticated, anon, public;