Rails下Doorkeeper OAuth2是否支持实现MFA多因素认证
结论
Doorkeeper 本身没有内置MFA相关的开箱功能,但它开放了全流程的自定义扩展钩子,完全可以在不侵入Doorkeeper核心代码的前提下,接入Google Authenticator TOTP、短信验证码这类MFA校验能力,完全兼容标准OAuth2流程。
具体实现方案
整个实现不需要改动Doorkeeper核心逻辑,只需要在用户身份校验环节插入MFA拦截步骤即可:
- 先给你的资源所有者模型(通常是
User模型)加MFA相关存储字段:
TOTP类校验(Google Authenticator)需要存储otp_secret(TOTP密钥)、otp_enabled(是否开启TOTP MFA)字段;短信类MFA需要存储mfa_bound_phone(绑定手机号)、sms_otp_code(短信验证码)、sms_otp_expires_at(验证码过期时间)字段,通过常规Rails数据库迁移添加即可,和Doorkeeper自带的表无冲突。 - 自定义Doorkeeper授权控制器,插入MFA前置校验:
Doorkeeper支持替换默认控制器实现,你可以自定义控制器继承Doorkeeper默认的授权控制器,在授权流程入口加MFA拦截逻辑,示例代码如下:# config/routes.rb 中自定义Doorkeeper路由映射 use_doorkeeper do controllers authorizations: 'custom_doorkeeper/authorizations' end# app/controllers/custom_doorkeeper/authorizations_controller.rb class CustomDoorkeeper::AuthorizationsController < Doorkeeper::AuthorizationsController before_action :intercept_for_mfa, only: [:new, :create] private def intercept_for_mfa current_user = current_resource_owner # 未登录、未开启MFA、当前会话已经完成MFA校验的,直接放行走原有流程 return if current_user.blank? return unless current_user.otp_enabled? || current_user.sms_mfa_enabled? return if session[:mfa_verified_for_user_id] == current_user.id # 暂存当前授权请求的全部参数,MFA校验完成后回跳使用 session[:pending_oauth_auth_params] = request.request_parameters.merge(request.query_parameters) # 跳转到MFA校验页,让用户选择TOTP/短信方式完成验证 redirect_to new_mfa_challenge_path end end - 实现独立的MFA校验逻辑:
- Google Authenticator类TOTP校验:直接用成熟的Ruby TOTP类库实现即可,校验用户输入的6位动态码和服务端存储的
otp_secret生成的动态码是否匹配即可。 - 短信MFA校验:用户触发发送时生成6位随机数字验证码,加密后存到对应用户字段,设置5-10分钟有效期,调用你接入的短信服务商接口下发,校验时比对验证码是否一致、是否在有效期内即可。
校验通过后,在session中写入mfa_verified_for_user_id: current_user.id的标记,取回之前暂存的授权请求参数,重定向回Doorkeeper授权路径,继续走原有的授权同意、授权码下发、令牌生成流程即可。
- Google Authenticator类TOTP校验:直接用成熟的Ruby TOTP类库实现即可,校验用户输入的6位动态码和服务端存储的
- 特殊场景兼容:
对client_credentials这类不需要用户参与的机器对机器授权模式,直接跳过MFA校验即可;对未开启MFA的用户,整个流程和原有逻辑完全一致,无感知。
落地注意事项
- 不要把MFA校验逻辑放在令牌交换(即code换token)的接口层:MFA属于用户交互阶段的身份增强校验,放在授权码下发前的用户侧流程才符合OAuth2标准规范,不会破坏现有客户端的兼容性。
- MFA校验通过的session标记必须和当前用户ID绑定:不要设置全局有效标记,避免出现跨账号、跨会话绕过的安全问题。
- 如果需要给不同安全等级的客户端配置强制MFA要求,可以配合Doorkeeper的scope机制,给高安全要求的客户端配置
mfa_required的scope,只有完成MFA校验的请求才允许下发对应scope的访问令牌。
内容的提问来源于stack exchange,提问作者alexanoid
相关产品推荐
相关产品推荐

