Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refs RE-2: User registration and user authentication are possible with OAuth authentication #42

Merged
merged 2 commits into from
Dec 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,8 @@ yarn-debug.log*
/docker-volumes/*
!/docker-volumes/.keep
stats.json

# ignore local settings
config/settings.local.yml
config/settings/*.local.yml
config/environments/*.local.yml
7 changes: 7 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,10 @@ gem 'cancancan'

# Settings plugin for Rails that makes managing a table of global keys. (https://github.com/huacnlee/rails-settings-cached)
gem 'rails-settings-cached', '~> 2.0'

gem 'omniauth', '~> 1.9'
gem 'omniauth-twitter', '~> 1.4'
gem 'omniauth-github', '~> 1.3'
gem 'omniauth-google-oauth2', '~> 0.8'

gem 'config'
73 changes: 73 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,12 @@ GEM
chunky_png (1.3.11)
coderay (1.1.2)
concurrent-ruby (1.1.5)
config (2.0.0)
activesupport (>= 4.2)
deep_merge (~> 1.2, >= 1.2.1)
dry-schema (~> 1.0)
crass (1.0.5)
deep_merge (1.2.1)
devise (4.7.1)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
Expand All @@ -94,10 +99,43 @@ GEM
warden (~> 1.2.3)
devise-i18n (1.8.2)
devise (>= 4.6)
dry-configurable (0.9.0)
concurrent-ruby (~> 1.0)
dry-core (~> 0.4, >= 0.4.7)
dry-container (0.7.2)
concurrent-ruby (~> 1.0)
dry-configurable (~> 0.1, >= 0.1.3)
dry-core (0.4.9)
concurrent-ruby (~> 1.0)
dry-equalizer (0.3.0)
dry-inflector (0.2.0)
dry-initializer (3.0.2)
dry-logic (1.0.5)
concurrent-ruby (~> 1.0)
dry-core (~> 0.2)
dry-equalizer (~> 0.2)
dry-schema (1.4.1)
concurrent-ruby (~> 1.0)
dry-configurable (~> 0.8, >= 0.8.3)
dry-core (~> 0.4)
dry-equalizer (~> 0.2)
dry-initializer (~> 3.0)
dry-logic (~> 1.0)
dry-types (~> 1.2)
dry-types (1.2.1)
concurrent-ruby (~> 1.0)
dry-container (~> 0.3)
dry-core (~> 0.4, >= 0.4.4)
dry-equalizer (~> 0.2, >= 0.2.2)
dry-inflector (~> 0.1, >= 0.1.2)
dry-logic (~> 1.0, >= 1.0.2)
erubi (1.9.0)
faraday (0.17.1)
multipart-post (>= 1.2, < 3)
ffi (1.11.1)
globalid (0.4.2)
activesupport (>= 4.2.0)
hashie (3.6.0)
htmlentities (4.3.4)
i18n (1.7.0)
concurrent-ruby (~> 1.0)
Expand All @@ -107,6 +145,7 @@ GEM
jaro_winkler (1.5.3)
jbuilder (2.9.1)
activesupport (>= 4.2.0)
jwt (2.2.1)
kramdown (1.17.0)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
Expand All @@ -125,9 +164,38 @@ GEM
mini_portile2 (2.4.0)
minitest (5.12.2)
msgpack (1.3.1)
multi_json (1.14.1)
multi_xml (0.6.0)
multipart-post (2.1.1)
nio4r (2.5.1)
nokogiri (1.10.5)
mini_portile2 (~> 2.4.0)
oauth (0.5.4)
oauth2 (1.4.2)
faraday (>= 0.8, < 2.0)
jwt (>= 1.0, < 3.0)
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (>= 1.2, < 3)
omniauth (1.9.0)
hashie (>= 3.4.6, < 3.7.0)
rack (>= 1.6.2, < 3)
omniauth-github (1.3.0)
omniauth (~> 1.5)
omniauth-oauth2 (>= 1.4.0, < 2.0)
omniauth-google-oauth2 (0.8.0)
jwt (>= 2.0)
omniauth (>= 1.1.1)
omniauth-oauth2 (>= 1.6)
omniauth-oauth (1.1.0)
oauth
omniauth (~> 1.0)
omniauth-oauth2 (1.6.0)
oauth2 (~> 1.1)
omniauth (~> 1.9)
omniauth-twitter (1.4.0)
omniauth-oauth (~> 1.1)
rack
orm_adapter (0.5.0)
paper_trail (10.3.1)
activerecord (>= 4.2)
Expand Down Expand Up @@ -286,12 +354,17 @@ DEPENDENCIES
byebug
cancancan
capybara (>= 2.15)
config
devise
devise-i18n
identicon
initial_avatar
jbuilder (~> 2.7)
listen (>= 3.0.5, < 3.2)
omniauth (~> 1.9)
omniauth-github (~> 1.3)
omniauth-google-oauth2 (~> 0.8)
omniauth-twitter (~> 1.4)
paper_trail (~> 10.3.0)
pg (~> 1.1)
pry
Expand Down
25 changes: 25 additions & 0 deletions app/controllers/omniauth_callbacks_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# refs: https://qiita.com/mnishiguchi/items/e15bbef61287f84b546e
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
# いくつプロバイダーを利用しようが処理は共通しているので本メソッドをエイリアスとして流用。
def callback_for_all_providers
unless request.env['omniauth.auth'].present?
flash[:danger] = 'Authentication data was not provided'
redirect_to root_url && return
end
provider = __callee__.to_s
user = OAuthService::GetOAuthUser.call(request.env['omniauth.auth'])
# ユーザーがデータベースに保存されており、且つemailを確認済みであれば、ユーザーをログインする。
if user.persisted? && user.email_verified?
sign_in_and_redirect user, event: :authentication
set_flash_message(:notice, :success, kind: provider.capitalize) if is_navigational_format?
else
# user.reset_confirmation!
flash[:warning] = t('.need_info_before_signup', default: 'We need your email address before proceeding.')
redirect_to finish_signup_path(user, provider: provider)
end
end

alias twitter callback_for_all_providers
alias github callback_for_all_providers
alias google_oauth2 callback_for_all_providers
end
25 changes: 25 additions & 0 deletions app/controllers/omniauth_finished_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# refs: https://qiita.com/mnishiguchi/items/e15bbef61287f84b546e
class OmniauthFinishedController < ApplicationController
skip_authorization_check only: [:finish_signup]
before_action :authenticate_user!, except: :finish_signup

def finish_signup
@user = User.find(params[:id])
@provider = params[:provider]

if (request.post? || request.patch?) && @user.update(user_params)
# @user.send_confirmation_instructions unless @user.confirmed?
sign_in(@user, bypass: true)
redirect_to root_url, notice: t('devise.omniauth_callbacks.success', kind: @provider.capitalize)
end
end

private

# user_paramsにアクセスするため。
def user_params
accessible = [ :username, :email ]
accessible << [ :password, :password_confirmation ] unless params[:user][:password].blank?
params.require(:user).permit(accessible)
end
end
10 changes: 10 additions & 0 deletions app/controllers/registrations_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# refs: https://qiita.com/mnishiguchi/items/e15bbef61287f84b546e
class RegistrationsController < Devise::RegistrationsController

protected

# Override
def update_resource(resource, params)
resource.update_without_password(params)
end
end
55 changes: 55 additions & 0 deletions app/helpers/o_auth/o_auth_policy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# refs: https://qiita.com/mnishiguchi/items/e15bbef61287f84b546e
module OAuthPolicy
class Base
attr_reader :provider, :uid, :name, :nickname, :email, :url, :image_url,
:description, :other, :credentials, :raw_info
end

class Twitter < OAuthPolicy::Base
def initialize(auth)
@provider = auth['provider']
@uid = auth['uid']
@name = auth['info']['name']
@nickname = auth['info']['nickname']
@email = ''
@url = auth['info']['urls']['Twitter']
@image_url = auth['info']['image']
@description = auth['info']['description'].try(:truncate, 255)
@credentials = auth['credentials'].to_json
@raw_info = auth['extra']['raw_info'].to_json
freeze
end
end

class Github < OAuthPolicy::Base
def initialize(auth)
@provider = auth['provider']
@uid = auth['uid']
@name = auth['info']['name']
@nickname = ''
@email = ''
@url = 'https://github.com/'
@image_url = auth['info']['image']
@description = ''
@credentials = auth['credentials'].to_json
@raw_info = auth['extra']['raw_info'].to_json
freeze
end
end

class GoogleOauth2 < OAuthPolicy::Base
def initialize(auth)
@provider = auth['provider']
@uid = auth['uid']
@name = auth['info']['name']
@nickname = ''
@email = ''
@url = 'https://google.com/'
@image_url = auth['info']['image']
@description = ''
@credentials = auth['credentials'].to_json
@raw_info = auth['extra']['raw_info'].to_json
freeze
end
end
end
16 changes: 16 additions & 0 deletions app/javascript/stylesheets/sb-admin/_login.scss
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,22 @@ form.user {

}

.omniauth {
.btn-user {
font-size: 0.8rem;
border-radius: 10rem;
padding: 0.75rem 1rem;
}
}

.btn-twitter {
@include button-variant($brand-twitter, $white);
}

.btn-github {
@include button-variant($brand-github, $white);
}

.btn-google {
@include button-variant($brand-google, $white);
}
Expand Down
2 changes: 2 additions & 0 deletions app/javascript/stylesheets/sb-admin/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ $cyan: #36b9cc !default;
// Custom Colors
$brand-google: #ea4335;
$brand-facebook: #3b5998;
$brand-github: #24292e;
$brand-twitter: rgba(29,161,242,1.00);

// Set Contrast Threshold
$yiq-contrasted-threshold: 195 !default;
Expand Down
62 changes: 62 additions & 0 deletions app/models/social_profile.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# refs: https://qiita.com/mnishiguchi/items/e15bbef61287f84b546e
# == Schema Information
#
# Table name: social_profiles
#
# id :integer not null, primary key
# user_id :integer
# provider :string
# uid :string
# name :string
# nickname :string
# email :string
# url :string
# image_url :string
# description :string
# others :text
# credentials :text
# raw_info :text
# created_at :datetime not null
# updated_at :datetime not null
#

class SocialProfile < ApplicationRecord
belongs_to :user
store :others

validates_uniqueness_of :uid, scope: :provider

def self.find_for_oauth(auth)
profile = find_or_create_by(uid: auth.uid, provider: auth.provider)
profile.save_oauth_data!(auth)
profile
end

def save_oauth_data!(auth)
return unless valid_oauth?(auth)

provider = auth["provider"]
policy = policy(provider, auth)

self.update_attributes( uid: policy.uid,
name: policy.name,
nickname: policy.nickname,
email: policy.email,
url: policy.url,
image_url: policy.image_url,
description: policy.description,
credentials: policy.credentials,
raw_info: policy.raw_info )
end

private

def policy(provider, auth)
class_name = "#{provider}".classify
"OAuthPolicy::#{class_name}".constantize.new(auth)
end

def valid_oauth?(auth)
(self.provider.to_s == auth['provider'].to_s) && (self.uid == auth['uid'])
end
end
Loading