You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Ruby on Rails单页应用中配置CSRF令牌实现Google登录

解决Rails + Devise Omniauth谷歌登录的CSRF令牌验证失败问题

方法一:自定义谷歌登录回调,手动携带CSRF令牌(推荐)

谷歌GSI默认通过data-login_uri发起的跨域POST请求无法自动携带Rails的CSRF令牌,导致验证失败。通过自定义回调函数,我们可以手动获取并携带令牌发起请求:

  1. 修改React登录组件
    移除data-login_uri,添加回调函数处理登录请求:
import React, { useEffect } from 'react';

const SignInWithGoogle = () => {
  useEffect(() => {
    // 挂载回调函数到window,供谷歌GSI调用
    window.handleCredentialResponse = (response) => {
      // 从页面meta标签获取Rails生成的CSRF令牌
      const csrfToken = document.querySelector('meta[name="csrf-token"]').content;
      
      // 发起带CSRF令牌的POST请求到Omniauth回调地址
      fetch('/users/auth/google_oauth2/callback', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          'X-CSRF-Token': csrfToken
        },
        body: new URLSearchParams({
          credential: response.credential,
          client_id: response.clientId
        })
      }).then(res => {
        // 根据响应处理后续逻辑,比如跳转用户面板
        if (res.ok) {
          window.location.href = '/dashboard';
        }
      }).catch(err => {
        console.error('谷歌登录失败:', err);
      });
    };
  }, []);

  return (
    <div className='sign-in-with-google'>
      <div id="g_id_onload"
          data-client_id="xxxxx.apps.googleusercontent.com"
          data-context="signup"
          data-ux_mode="popup"
          data-callback="handleCredentialResponse"
          data-auto_prompt="false">
      </div>

      <div className="g_id_signin"
          data-type="standard"
          data-shape="rectangular"
          data-theme="outline"
          data-text="signin_with"
          data-size="large"
          data-logo_alignment="left">
      </div>
    </div>
  );
};

export default SignInWithGoogle;
  1. 确保页面包含CSRF meta标签
    检查application.html.erb的<head>区域,确认存在Rails自动生成的CSRF标签(默认已添加,若缺失则手动加入):
<head>
  <%= csrf_meta_tags %>
  <!-- 其他头部内容 -->
  <script src="https://accounts.google.com/gsi/client" async defer></script>
</head>

方法二:跳过Omniauth回调的CSRF验证(不推荐)

此方法会降低应用安全性,仅建议测试环境临时使用:
修改Omniauth回调控制器,跳过谷歌登录路由的CSRF验证:

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  # 仅跳过谷歌回调的CSRF验证
  skip_before_action :verify_authenticity_token, only: [:google_oauth2]

  def google_oauth2
    # 你的谷歌登录回调逻辑,例如创建/查找用户
    @user = User.from_omniauth(request.env["omniauth.auth"])
    if @user.persisted?
      sign_in_and_redirect @user, event: :authentication
      set_flash_message(:notice, :success, kind: "Google") if is_navigational_format?
    else
      session["devise.google_data"] = request.env["omniauth.auth"].except(:extra)
      redirect_to new_user_registration_url
    end
  end
end

内容的提问来源于stack exchange,提问作者StaticMethod

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 17:27:51