首页 > 解决方案 > 我如何连接一个 React 按钮以使用 Devise Token Auth + OmniAuth 进行身份验证

问题描述

我无法将我的 Devise Token Auth 与我从谷歌返回的令牌连接起来。

我将这个包用于按钮: https ://www.npmjs.com/package/react-google-login

这是我要设置的身份验证: https ://github.com/lynndylanhurley/devise_token_auth/blob/master/docs/config/omniauth.md

我收到了来自谷歌的响应按钮的回复,但我不知道这些信息必须如何翻译才能返回到设计身份验证。

这两种技术之间严重缺乏在线信息。它归结为如何将这个 ruby​​ 标签翻译成反应:

<%= link_to "Sign in with Google", user_google_oauth2_omniauth_authorize_path, method: :post %>

标签: reactjsdevisedevise-token-authomniauth-google-oauth2react-google-login

解决方案


我知道这是旧的,但这是我的 2 美分。

我使用了这个 gem OmniAuth Google OAuth2。信息很清楚。在我的项目中,我使用 JWT 管理我的令牌,同时仍然存储来自 Google 的访问和刷新令牌。

后端

# config/initializers/devise.rb
config.omniauth :google_oauth2,
                ENV['GOOGLE_CLIENT_ID'],
                ENV['GOOGLE_CLIENT_SECRET'],
                { scope: "userinfo.email, userinfo.profile",
                  prompt: 'select_account',
                  image_aspect_ratio: 'square',
                  provider_ignores_state: true,
                }
# controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController

  def google_oauth2
    @user = User.from_omniauth(request.env['omniauth.auth'])

    if @user.persisted?
      # My personal token
      token = issue_token(@user)
      render json: { success: true,
                     user: @user,
                     token: token,
                     google_token: @user.access_token,
                     message: "Logged in successfully." }
    else
      render json: { success: false,
                     error: @user.errors.full_messages.join("\n"),
                     message: 'Google sign in unsuccessful.' }
    end
  end

  def failure
    set_flash_message! :alert, :failure, kind: OmniAuth::Utils.camelize(failed_strategy.name), reason: failure_message
    render json: { success: false, message: 'Google authentication failed.', reason: failure_message, kind: OmniAuth::Utils.camelize(failed_strategy.name) }
  end

  private

end
# In User.rb
  def self.from_omniauth(auth)

    user = User.where(email: auth.info.email).first

    if user
      user = User.update(id: user.id,
                         refresh_token: auth.credentials.refresh_token,
                         access_token: auth.credentials.token,
                         uid: auth.uid,
                         )
    else
      # Create a username from names, append incremental if username already exists
      username ||= auth.info.first_name + auth.info.last_name
      username = username.delete('^a-zA-Z0-9_').downcase
      num = 1
      until User.find_by(username: username).nil?
        username = "#{username}#{num}"
        num += 1
      end

      user = User.create(email: auth.info.email,
                         uid: auth.uid,
                         refresh_token: auth.credentials.refresh_token,
                         access_token: auth.credentials.token,
                         provider: auth.provider,
                         password: Devise.friendly_token[0, 20],
                         firstname: auth.info.first_name,
                         lastname: auth.info.last_name,
                         username: username,
                         )
    end
    user
  end
    # routes.rb
    # User Routes: Devise
    devise_for :users,
               path_names: {
                 sign_in: 'login',
                 sign_out: 'logout',
                 # sign_up: 'register'
               },
               controllers: {
                 sessions: 'users/sessions',
                 registrations: 'users/registrations',
                 omniauth_callbacks: 'users/omniauth_callbacks'
               }

以上路线翻译

user_google_oauth2_omniauth_authorize_path  GET|POST    /api/users/auth/google_oauth2(.:format) 
users/omniauth_callbacks#passthru

user_google_oauth2_omniauth_callback_path   GET|POST    /api/users/auth/google_oauth2/callback(.:format)    
users/omniauth_callbacks#google_oauth2

这是前端

<!-- index.html -->
<head>
  <script src="https://apis.google.com/js/platform.js?onload=init" async defer></script>
</head>

不用担心定义gapi函数,它script在上面加载

// RegisterContent.js
const RegisterContent = function RegisterContent() {

     function handleResponse(response) {
         // Save user to redux store and all the tokens to cookies
     }

    // callback
    function signInCallback(authResult) {
        if (authResult.code) {
            const params = { code: authResult.code }
            const path = "localhost:3000/api/users/auth/google_oauth2/callback";
            // This just handdles posting with axios 
            postResource(path, params, handleResponse);
        }
    }

    // This will prompt opening the google window and returns a callback upon success
    const googleHandler = () => {
        googleAuth.grantOfflineAccess().then(signInCallback);
    };

    useEffect(() => {
        // Initialize the GoogleAuth object
        gapi.load("auth2", function foo() {
            const auth = gapi.auth2.init({
                client_id: process.env.REACT_APP_GOOGLE_CLIENT_ID,
                scope: "email profile",
            });
            setGoogleAuth(auth);
            console.log("Init");
        });
    }, []);

    return (
        <Button onclick={googleHandler}>
            Continue with Google
        </Button>
    
    );

}

一些帮助Google Sign-In JavaScript 客户端参考的资源, 如何将 Google API 集成到您的 React 应用中,仅此而已。


推荐阅读