環境
API
- Rails6.0
フロント
- React
目的
Omniauthを用いたSNS認証でのユーザー登録で初回ログイン時にSNS上のアカウント情報から一部変更したり追加情報の入力を促したりしたい。
devise_auth_tokenを用いているが、deviseでも基本は同じように設計していいと思う。
実装方法
①usersテーブルにTrackable系のカラムを追加する
class AddColumnsToUsers < ActiveRecord::Migration[6.0]
def change
add_column :users, :sign_in_count, :integer, default: 0, null: false
add_column :users, :current_sign_in_at, :datetime
add_column :users, :last_sign_in_at, :datetime
add_column :users, :current_sign_in_ip, :string
add_column :users, :last_sign_in_ip, :string
end
end
これらのカラムを追加。上から順に
- サインイン回数
- 現在のログインをした日時
- 最後にログインした日時
- 現在のログイン元IPアドレス
- 最後のログインしたときのログイン元IPアドレス
の情報を持っている
②models/user.rbにてtrackableを設定
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable, :trackable, #←これ
:recoverable, :rememberable, :validatable, :omniauthable, omniauth_providers: [:twitter]
モデルにも設定が必要。逆に言うとこれだけでサインイン時に勝手にカラムに値が入っていく。
③omniauthでの認証時にユーザーが初回ログインかどうかを判定する
def render_data_or_redirect(message, data, user_data = {})
# 初回ログイン時にはcookieに情報をセット。Oauth認証後ユーザー情報の編集ページに飛ばす
cookies[:first_session] = { value: true, path: root_path, expres: 10.minutes } if @resource.sign_in_count == 0
devise_auth_tokenではomniauth_callbacksコントローラーでユーザーが認証できた場合に
render_data_or_redirectメソッドが呼ばれる。このメソッドでアプリ側のページに返す直前で
保存したユーザーのsign_in_countが0の場合にCookie上にfirst_sessionという値を仕込む。期限は10分とかにしとく
④フロント側でCookieから初回ログインのtmpデータを取得する
class App extends React.Component {
componentDidMount() {
const cookies = new Cookies();
// ユーザー認証が済んでいる場合
if (authToken) {
if (cookies.get('first_session')) {
// 実際にはユーザー情報編集ページに飛ばす処理を入れる。次のブランチで
alert('初回ログイン')
}
// 中略
return authToken
} else {
return null
}
}
今回はルートコンポーネントのAppでログイン済みかどうかの判定をするので、
そこにcookieの中にfirst_sessionが存在しているかどうかの判定を行う条件式を実装。
なお、Cookieを読み込むライブラリとしては事前にuniversal-cookieを導入している。
npm install universal-cookie
⑤2回目以降のログイン時にCookieのtmpデータを削除する
tmpデータの有効期限が10分とかにしてるので、10分以内に2回ログインされることも想定して2回目以降のログインでは
Cookieのデータを削除するようにした。
# 2回目以降のログイン時にはfirst_sessionのクッキーデータを削除
cookies.delete(:first_session, path: root_path) if cookies[:first_session]
挙動
感想
思ったよりかんたんにできた。
Trackable系のカラムちゃんと使ったことなかったのでこういう使い方ができるのか、と感動した。
Cookieを使って条件分岐しているのでセキュリティ的にどうなの?とかはあるけど一旦置いておく。