reCAPTCHA

Odoo Google reCAPTCHA 为什么不只是“加个验证码”而已:分数阈值、动作校验与失败回退边界讲透

很多团队把 reCAPTCHA 当成表单上的一个外挂控件,但 Odoo 真正关注的是公开 key 下发、服务端二次校验、动作名一致性、分数阈值与异常时的用户反馈边界。

框架
进阶 开发者 2 分钟阅读
0 评论 0 点赞 0 收藏 5 阅读

先说结论

Odoo 的 google_recaptcha 不是“前端插一个 Google 小组件”这么简单。

/home/ubuntu/odoo-temp/addons/google_recaptcha/models/ir_http.py 可以看到,官方真正搭的是一个服务端收口流程:

  • 先决定 public key 要不要下发给前端
  • 请求到达时再从服务端验证 token
  • 除了看 success,还看 score
  • 还会检查 token 产生时的 action 是否和当前业务动作一致
  • 最后再把不同失败类型转换成不同报错

所以最短结论是:

在 Odoo 里,reCAPTCHA 不是一个 UI 控件,而是一条“前端采样、后端裁决”的风控链。


为什么 public key 不是无脑下发

_add_public_key_to_session_info() 会读取:

  • enable_recaptcha
  • recaptcha_public_key

只有:

  • 功能开着
  • 而且 public key 存在

它才把 recaptcha_public_key 放进 session_infofrontend_session_info

这个判断看起来很简单,但很有平台味道。

因为 Odoo 没把 reCAPTCHA 设计成“前端自己决定要不要展示”,而是把开关和 key 都留在后端配置里,由后端明确告诉前端:

  • 该不该启用
  • 启用时该拿哪把公钥

这能避免几种常见混乱:

  • 前端页面还在尝试调用 reCAPTCHA,但后端其实已经关掉了
  • 公钥没配好,页面仍然盲目初始化
  • 测试环境和生产环境公钥混用

为什么真正关键的是服务端校验,而不是前端拿到 token

_verify_request_recaptcha_token(action) 才是主入口。

它会:

  1. 再次检查 enable_recaptcha
  2. 从当前请求参数里取出 recaptcha_token_response
  3. 取客户端 IP
  4. _verify_recaptcha_token(ip, token, action) 去 Google 验证
  5. 根据结果决定放行还是抛错

这说明一个核心原则:

  • 前端拿到 token 只是“采样完成”
  • 只有后端核验通过,业务请求才算可信

所以如果你把 reCAPTCHA 只理解成“前端上有个 token 字段”,那就低估它了。Odoo 真正在意的是:

业务动作最终要由服务端基于外部验证结果来裁决。


为什么 Odoo 不只看 success,还要看 score

_verify_recaptcha_token() 调的是 v3 验证接口,返回的不只是成功 / 失败,还有分数。

Odoo 会把结果与 recaptcha_min_score 比较:

  • 分数高于阈值,判为 is_human
  • 分数低于阈值,判为 is_bot

这非常重要,因为 v3 的核心思想本来就不是“勾选我不是机器人”,而是“给这次行为打一分”。

所以运营上最常见的误区是:

  • 把 reCAPTCHA 当成绝对真 / 假判断

但 Odoo 的实现已经明确告诉你:

  • 它是风险评分
  • 你的系统要决定阈值
  • 阈值太高会误伤真人
  • 阈值太低会放进噪音请求

换句话说,这里真正的产品决策不是“是否启用 reCAPTCHA”,而是“你愿意接受多高的风险”


为什么还要校验 action

源码在 res_success and action and result['action'] 这段逻辑里,还会检查 token 的 action 是否等于当前验证动作。

这一步很多人会忽略,但它非常关键。

因为如果不核对 action,就可能出现一种跨场景复用:

  • 用户在一个低风险页面拿到 token
  • 攻击者把这个 token 拿去提交另一个高风险动作

一旦 action 不绑定具体业务操作,token 的上下文就会变模糊。

Odoo 在这里做的是:

  • token 不只要是真的
  • 还要证明它是“为这次动作拿到的”

这叫上下文一致性,不只是验证码有效性。


为什么不同错误要转成不同用户反馈

Odoo 没把所有失败都粗暴显示成“验证码失败”。

它会区分:

  • wrong_secret
  • wrong_token
  • timeout
  • bad_request
  • is_bot

对应抛出 ValidationErrorUserError,提示也不同。

这带来两个好处:

对用户

用户能知道是:

  • 请求超时了
  • 参数错了
  • 还是系统怀疑行为异常

对运维

你也更容易判断:

  • 是配置错了私钥
  • 还是前端没把 token 带上
  • 还是 Google 接口波动
  • 还是确实有风险流量进来

平台机制里,错误分型本身就是可运维性的一部分


为什么“没配私钥”会被视为 no_secret

_verify_recaptcha_token() 发现 recaptcha_private_key 为空时,直接返回 no_secret

这意味着在 Odoo 的模型里,reCAPTCHA 的真正生效条件不是“前端看到组件”,而是:

  • 公钥能下发
  • 私钥能校验
  • 功能开关没关闭

缺任何一块,都不算完整启用。

这也是排错时很容易忽略的一点:

  • 页面上看到了前端行为
  • 并不代表后端风控已经真正工作

新手最容易误解的 5 件事

1. 误以为 reCAPTCHA 是前端能力

真正做放行 / 拒绝决定的是后端。

2. 误以为 success=true 就足够

Odoo 还看 score,低分仍然会拒绝。

3. 误以为 token 只要有效就能到处复用

源码明确还要检查 action 是否匹配。

4. 误以为所有失败提示都该一样

不同错误分型对用户体验和运维排查都很重要。

5. 误以为 public key 配好了就算启用完成

没有 private key,服务端根本无法形成闭环验证。


实战排错顺序

如果你碰到“页面明明带了 token,却总被拦截”这类问题,建议按这个顺序查:

  1. 先看 enable_recaptcha 是否真的开启
  2. 确认 public key 和 private key 是否成对配置
  3. 检查请求里有没有 recaptcha_token_response
  4. 核对当前 action 名与前端申请 token 时是否一致
  5. recaptcha_min_score 是否设得过高
  6. 再区分是 timeout、bad_request 还是 is_bot

一句话记忆

Odoo Google reCAPTCHA 的重点不是“页面上多一个验证码”,而是用 score、action 和服务端判定,把公开表单流量收进一条真正可调参的风控链。

DISCUSSION

评论区

想参与讨论?先 登录 再发表评论。
还没有评论,你可以成为第一个留言的人。