노래하듯 이야기하고, 춤추듯 정복하라.

[Ruby On Rails] 소셜 SNS 인증 _Naver 본문

프로그래밍/Ruby & Rails

[Ruby On Rails] 소셜 SNS 인증 _Naver

hyeoke 2019. 1. 25. 16:42

[소셜 SNS 인증]

- 참고 링크: http://blog.naver.com/kbs4674/221446312846


# 인사

안녕하세요 모닝버드입니다. 오늘도 어제에 이어서 포스팅을 이어나갑니다. 간만에 연속 포스팅이네요 :)

오늘은 레일즈 애플리케이션에서 소셜 SNS 인증하는 방법에 대해 알아보겠습니다. 생각보다 많이 복잡한 편은 아닙니다. 아직 코드 전체를 이해하진 못했지만 대략적인 원리는 파악 가능합니다.


# 사전 준비

- Devise 젬이 설치 및 세팅되어 있다는 상황을 가정


# 진행

1. 네이버 개발자 페이지 로그인

- https://developers.naver.com/products/login/api/


2. 네이버 개발자 도구에 애플리케이션 등록

* 참고 링크: https://blog.naver.com/kbs4674/221209557339

- 콜백 링크: /users/auth/naver/callback (Ex=> http://localhost:3000/users/auth/naver/callback)


3. 젬 설치

Gemfile에 젬 추가 후 $ bundle install 진행, figaro 젬은 application.yml에 저장되는 네이버 고유 키(Client ID, Client Secret Key)를 노출시키지 않도록 해주는 기능을 담당한다.

gem 'omniauth', '~> 1.9'
gem 'omniauth-naver', '~> 0.2.0'
gem 'figaro', '~> 1.1', '>= 1.1.1'

* Tip: 필자는 보통 젬을 추가할 때 버전을 명시 합니다. 이유는 나중에 새로운 젬을 설치할 시 버전이 명시되어 있지 않으면, 버전 업 되거나 변경되기 일수입니다. 그럴 때 마다 서로 충돌이 일으키는 젬들이 발생하는데, 버전을 명시 하면 추후 일어날 불상사를 어느정도 막을 수 있지 않을까 생각듭니다. / 항상 bundle install 후에는 서버 재부팅 하기


4. 터미널에 명령어 입력

2번 째 줄 같은 경우 네이버닉네임(or이름)을 저장할 field가 User모델에 있으면 생략하세요!

$ rails generate devise:controllers users
$ rails g migration add_name_to_users name:string
$ rails g model identity user:references provider:string uid:string


5. db/migrate/(기간)_devise_create_users.rb 수정 -> 주석 해제

# Trackable
      t.integer  :sign_in_count, default: 0, null: false
      t.datetime :current_sign_in_at
      t.datetime :last_sign_in_at
      t.string   :current_sign_in_ip
      t.string   :last_sign_in_ip


6. config/application.rb -> 네이버 클라이언트 ID, 네이버 시크릿 키 입력

* 참고 링크: https://blog.naver.com/kbs4674/221209557339

NAVER_CLIENT_ID: "(API CLIENT 아이디)"
NAVER_ClIENT_SECRET: "(API CLIENT 암호)"


7. config/initializers/devise.rb

config.omniauth :naver, ENV["NAVER_CLIENT_ID"], ENV["NAVER_ClIENT_SECRET"]


8. config/routes.rb 에서 devise_for :users 부분 수정

devise_for :users, :controllers => { omniauth_callbacks: 'users/omniauth_callbacks' }


9. app/models/identity.rb 수정 -> 코드추가

validates_presence_of :uid, :provider
validates_uniqueness_of :uid, :scope => :provider
 
def self.find_for_oauth(auth)
  find_or_create_by(uid: auth.uid, provider: auth.provider)
end


10. app/models/user.rb에 코드 추가

- devise 세팅 추가 -> :omniauthable

devise :database_authenticatable, :registerable,
       :recoverable, :rememberable, :trackable, :validatable, :omniauthable

- naver에서 허용한 개인정보 가져와서 저장하기

* 네이버에서 공개하는 데이터: birthday(출생)와 age(나이정보)를 제공하지만 제한적으로 제공해 줌(auth.extra.raw_info.response.age => 20~29, auth.extra.raw_info.response.birthday => 09-02)

  has_many :identities, dependent: :destroy

  def self.find_for_oauth(auth, signed_in_resource = nil)
    # user와 identity가 nil이 아니라면 받는다
    identity = Identity.find_for_oauth(auth)
    user = signed_in_resource ? signed_in_resource : identity.user

    # user가 nil이라면 새로 만든다.
    if user.nil?
      # 이미 있는 이메일인지 확인한다.
      email = auth.info.email
      user = User.where(:email => email).first
      unless self.where(email: auth.info.email).exists?
        # test
        puts "====================================================="
        puts auth
        puts "====================================================="

        # 없다면 새로운 데이터를 생성한다.
        if user.nil?
          user = User.new(
            email: auth.info.email,
            password: Devise.friendly_token[0,20]
          )
          user.skip_confirmation!
          user.save!
        end
      end
      end

    if identity.user != user
      identity.user = user
      identity.uid = (0...8).map { (65 + rand(26)).chr }.join
      identity.save!
    end
    user
  end

  def email_required?
    false
  end

  def email_changed?
    false
  end


11. app/controllers/users/omniauth_callbacks_controller.rb

  def self.provides_callback_for(provider)
    class_eval %Q{
      def #{provider}
        @user = User.find_for_oauth(request.env["omniauth.auth"], current_user)
 
        if @user.persisted?
          sign_in_and_redirect @user, event: :authentication
          set_flash_message(:notice, :success, kind: "#{provider}".capitalize) if is_navigational_format?
        else
          session["devise.#{provider}_data"] = request.env["omniauth.auth"]
          redirect_to new_user_registration_url
        end
      end
    }
  end
 
  [:naver].each do |provider|
    provides_callback_for provider
  end
 
  def after_sign_in_path_for(resource)
      root_path
  end


# 포스팅을 마치며

이 포스팅에 앞서 페이스북 인증도 구현해 보았는데, 결과적으로 레일즈에서 소셜 SNS 인증을 개발하는 부분은 각 SNS 플랫폼 별로 큰 차이가 없다. 다만 설치하는 Gem 이 살짝 다르고, omniauth_callbacks_controller에서 서비스 인증에 적용된 SNS provide(Ex=> [:naver, :facebooe, :google])을 제대로 설정해줘야한다. 그리고 user.rb에서 SNS 플랫폼에서 가져오는 회원 정보에 따라 사용자 정보 저장 세팅을 달리 해 줘야 한다.


.

.


< Contact: 레일즈 서비스 개발 및 스타트업 관련 문의 >

- Email: hyeok0902e@gmail.com

Comments