Rails6 devise && omniauth && google-oauth2를 이용해 인증로직을 구현해보자

Posted by negabaro kim on Wednesday, August 19, 2020 Tags: rails devise   3 minute read

이번 포스트에서는 devise && omniauth google oauth2를 이용해 인증로직을 구현하는 방법에 대해 알아보자.

이 포스트에서는 devise의 기본설정이 끝난상태를 전제로 설명한다.

devise의 인스톨 방법은 Rails devise인스톨 방법를 참조바란다.

Gemfile

gem "devise"
gem 'omniauth' #add
gem 'omniauth-google-oauth2' #add

User의 migrate설정

Rails devise인스톨 방법 설정후 아래의 컬럼을 추가해줘야한다.(meta는 필수아님)

t.string :provider,
t.string :uid,
t.string :token,
t.text :meta

controller설정

아래와 같은 컨트롤러를 추가해준다.

`find_for_google`은 모델설정에서 후술


```ruby
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def google
    @user = User.find_for_google(request.env['omniauth.auth'])

    if @user.persisted?
      flash[:notice] = I18n.t 'devise.omniauth_callbacks.success', kind: 'Google'
      sign_in_and_redirect @user, event: :authentication
    else
      session['devise.google_data'] = request.env['omniauth.auth']
      redirect_to new_user_registration_url
    end
  end
end

config/routes.rb

루팅설정에서 위에서 추가해준 컨트롤러의 패스를 넣어준다.

Rails.application.routes.draw do
  devise_for :users, controllers: {
    omniauth_callbacks: "users/omniauth_callbacks"
  }
end

app/models/user.rb

모델은 아래와 같이추가 meta는 필수항목이 아니므로 삭제해도 좋다.

class User < ApplicationRecord
  devise :omniauthable, omniauth_providers: %i(google)

  protected
  def self.find_for_google(auth)
    user = User.find_by(email: auth.info.email)

    unless user
      user = User.create(email:     auth.info.email,
                         provider: auth.provider,
                         uid:      auth.uid,
                         token:    auth.credentials.token,
                         meta:     auth.to_yaml)
    end
    user
  end
end

config/initializers/devise.rb

google_oauth2를 위한 설정이다. skip_jwt: true넣어주지 않으면 Invalid iat에러 발생함. 에러내용은 마지막에 설명함.

  config.omniauth :google_oauth2,
                  ENV['GOOGLE_APP_ID'], 
                  ENV['GOOGLE_APP_SECRET'],
                  skip_jwt: true,
                  name: :google,
                  scope: %w(email) 

.envrc

환경변수 추가

GOOGLE_APP_ID와GOOGLE_APP_SECRET의 값은 Google Developers Console에서 프로젝트 생성 -> 인증정보를 추가함으로 얻을 수 있다. 자세한 설명은 생략

GOOGLE_APP_ID='*************************************************'
GOOGLE_APP_SECRET='*****************'

view

아무 view에서 user_google_omniauth_authorize_path링크를 클릭시 google login을 진행한다.

존재하지 않은 email로 로그인을 하면 회원가입처리된후 user_signed_in?에 의해 logout라는 메시지가 나올것이다.

= link_to 'Signin with Google', user_google_omniauth_authorize_path
- if user_signed_in?
  h1 logout
- else
  h1 no login

메모

meta컬럼은 필수가 아님.

google에서 받을 수 있는 정보를 yaml형태로 모두 meta정보에 넣고 있는듯 참고용도로 추가했으며 필수설정은 아니다.

undefined method `current_sign_in_at’ devise에러

:trackable을 삭제하면 위에러가 발생하지 않았다.

Invalid iat에러

raise(JWT::InvalidIatError, 'Invalid iat') if !iat.is_a?(Numeric) || iat.to_f > Time.now.to_f

config설정에서 skip_jwt: true추가해주면 해결

config.omniauth :google_oauth2, ENV["GOOGLE_ID"], ENV["GOOGLE_SECRET"], skip_jwt: true

https://github.com/zquestz/omniauth-google-oauth2/issues/197#issuecomment-148629219