NoMethodError(nil:NilClass 的未定义方法“过期?”):仅使用 React 的 Rails 7 API OmniAuth 出现错误

问题描述 投票:0回答:2

我在仅 API Rails 应用程序中实现 OAuth 方面得到了巨大帮助,并以 React 作为前端。互联网上没有太多可用的文档,所以我度过了一段艰难的时光。

附注我没有使用设备。

这是我的代码库:

宝石:

gem 'omniauth-google-oauth2'
gem 'omniauth-rails_csrf_protection'
gem 'omniauth'

nutrition-backend/app/models/patient.rb
(型号):

class Patient < ApplicationRecord
  has_many :appointments
  has_many :records
  has_many :dietitians, through: :appointments

  validates :first_name, presence: true
    validates :last_name, presence: true
    validates :email, presence: true, uniqueness: true
    validates :password, presence: true, confirmation: true, on: :create

    has_secure_password

    validate :unique_email_across_models, on: :create

    private

    def unique_email_across_models
            if Dietitian.exists?(email: email) || Patient.exists?(email: email)
                    errors.add(:email, 'is already taken')
            end
    end
end

nutrition-backend/app/controllers/sessions_controller.rb

class SessionsController < ApplicationController
    skip_before_action :check_auth

  def google_oauth_callback
    binding.break
    auth = request.env['omniauth.auth']

    if auth.present?
      email = auth.info.email
      dietitian = Dietitian.find_by(email: email)

      if dietitian
        # If the dietitian already exists, sign in
        token = generate_token(dietitian)
        render json: { token: token, dietitian: dietitian.as_json(only: [:id, :first_name, :last_name, :email]) }, status: :ok
      else
        # If the dietitian doesn't exist, you can handle this case accordingly
        render json: { error: 'Dietitian not found' }, status: :not_found
      end
    else
      render json: { error: 'Authentication failed' }, status: :unprocessable_entity
    end
  end

  private

  def generate_token(user)
    # Using a JWT library to generate a token
    payload = { user_id: user.id }
    JWT.encode(payload, Rails.application.credentials.secret_key_base, 'HS256')
  end
end

nutrition-backend/config/initializers/omniauth.rb

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :google_oauth2, '1097164830695-qu5q175nq3r8bc5qvgo180n3lkvt1p8o.apps.googleusercontent.com', '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',
  {
    callback_path: '/auth/google_oauth2/callback', provider_ignores_state: Rails.env.development?
  }
end

路线:

get '/auth/google_oauth2/callback', to: 'sessions#google_oauth_callback'

最初我收到一个错误:

OmniAuth::NoSessionError (You must provide a session to use OmniAuth.):
但能够通过在
application.rb

中添加以下代码来调试它
config.middleware.use ActionDispatch::Cookies
config.middleware.use ActionDispatch::Session::CookieStore

但是,在那之后,我现在遇到的错误是:

D, [2023-09-23T11:43:37.562107 #32293] DEBUG -- omniauth: (google_oauth2) Callback phase initiated.
E, [2023-09-23T11:43:37.565538 #32293] ERROR -- omniauth: (google_oauth2) Authentication failure! undefined method `expired?' for nil:NilClass: NoMethodError, undefined method `expired?' for nil:NilClass

NoMethodError (undefined method `expired?' for nil:NilClass):

我尝试将

skip_before_action :verify_authenticity_token
添加到我的会话控制器,但没有解决问题。

有关其他上下文,这是我的 FRONTEND 代码库:

import { useState } from 'react';
import axios from 'axios';
import { GoogleOAuthProvider, GoogleLogin } from '@react-oauth/google';

function Auth() {
    const [token, setToken] = useState(null);

    const handleGoogleSuccess = async (response) => {
        try {

        const { data } = await axios.post('http://localhost:3000/auth/google_oauth2/callback', { response });
        const { token } = data;
        setToken(token);
        } catch (error) {
        console.error('Google OAuth Backend error:', error);
        }
    };

    return (
        <div>
            {token ? (
                // Rendered content for authenticated user
                <p>You are logged in!</p>
            ) : (
                // Rendered content for non-authenticated user
                <div>
                    <GoogleOAuthProvider clientId="1097164830695-qu5q175nq3r8bc5qvgo180n3lkvt1p8o.apps.googleusercontent.com">
                        <GoogleLogin onSuccess={handleGoogleSuccess} onFailure={(error) => console.error('Google OAuth failure:', error)} />
                    </GoogleOAuthProvider>
                </div>
            )}
        </div>
  );
}

export default Auth;

全堆栈跟踪/错误

Started POST "/auth/google_oauth2/callback" for ::1 at 2023-09-24 10:56:38 +0800
  ActiveRecord::SchemaMigration Pluck (0.7ms)  SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
D, [2023-09-24T10:56:38.747453 #10352] DEBUG -- omniauth: (google_oauth2) Callback phase initiated.
E, [2023-09-24T10:56:38.750371 #10352] ERROR -- omniauth: (google_oauth2) Authentication failure! undefined method `expired?' for nil:NilClass: NoMethodError, undefined method `expired?' for nil:NilClass

NoMethodError (undefined method `expired?' for nil:NilClass):

omniauth-oauth2 (1.8.0) lib/omniauth/strategies/oauth2.rb:92:in `callback_phase'
omniauth (2.1.1) lib/omniauth/strategy.rb:272:in `callback_call'
omniauth (2.1.1) lib/omniauth/strategy.rb:194:in `call!'
omniauth (2.1.1) lib/omniauth/strategy.rb:169:in `call'
omniauth (2.1.1) lib/omniauth/builder.rb:44:in `call'
rack (2.2.8) lib/rack/session/abstract/id.rb:266:in `context'
rack (2.2.8) lib/rack/session/abstract/id.rb:260:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/cookies.rb:704:in `call'
rack (2.2.8) lib/rack/etag.rb:27:in `call'
rack (2.2.8) lib/rack/conditional_get.rb:40:in `call'
rack (2.2.8) lib/rack/head.rb:12:in `call'
activerecord (7.0.8) lib/active_record/migration.rb:638:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/callbacks.rb:27:in `block in call'
activesupport (7.0.8) lib/active_support/callbacks.rb:99:in `run_callbacks'
actionpack (7.0.8) lib/action_dispatch/middleware/callbacks.rb:26:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/actionable_exceptions.rb:17:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/debug_exceptions.rb:28:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/show_exceptions.rb:29:in `call'
railties (7.0.8) lib/rails/rack/logger.rb:40:in `call_app'
railties (7.0.8) lib/rails/rack/logger.rb:25:in `block in call'
activesupport (7.0.8) lib/active_support/tagged_logging.rb:99:in `block in tagged'
activesupport (7.0.8) lib/active_support/tagged_logging.rb:37:in `tagged'
activesupport (7.0.8) lib/active_support/tagged_logging.rb:99:in `tagged'
railties (7.0.8) lib/rails/rack/logger.rb:25:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/remote_ip.rb:93:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/request_id.rb:26:in `call'
rack (2.2.8) lib/rack/runtime.rb:22:in `call'
activesupport (7.0.8) lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/server_timing.rb:61:in `block in call'
actionpack (7.0.8) lib/action_dispatch/middleware/server_timing.rb:26:in `collect_events'
actionpack (7.0.8) lib/action_dispatch/middleware/server_timing.rb:60:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/static.rb:23:in `call'
rack (2.2.8) lib/rack/sendfile.rb:110:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/host_authorization.rb:138:in `call'
rack-cors (2.0.1) lib/rack/cors.rb:102:in `call'
railties (7.0.8) lib/rails/engine.rb:530:in `call'
puma (5.6.7) lib/puma/configuration.rb:252:in `call'
puma (5.6.7) lib/puma/request.rb:77:in `block in handle_request'
puma (5.6.7) lib/puma/thread_pool.rb:340:in `with_force_shutdown'
puma (5.6.7) lib/puma/request.rb:76:in `handle_request'
puma (5.6.7) lib/puma/server.rb:443:in `process_client'
puma (5.6.7) lib/puma/thread_pool.rb:147:in `block in spawn_thread'
reactjs ruby-on-rails oauth-2.0 oauth google-oauth
2个回答
0
投票

你的谷歌在前端的响应是什么样的?包括吗

{
    code: 'YOUR_JWT_ID_TOKEN'
}

这是因为谷歌omniauth通过

搜索它

验证者=正文&&正文['代码']


0
投票

可能对遇到同样问题的人有帮助 - 我在类似的条件下遇到了同样的错误;然而,在 localhost 上它工作得很好,而在 生产 服务器上它不是

问题是我的生产 Rails 凭证中的符号错误

google.appId
。因此,我建议仔细检查您的
appId/secret key
的可用性和正确性,这很有可能会有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.