LoginSignup
2
0

More than 5 years have passed since last update.

devise_token_auth+omniauthで独自パラメータを付加したかった

Posted at

facebook/twitter/googleなどでログイン/ログアウトが出来るようになったものの、ログイン時にグループID的なやつを付けないと色々と問題が発生することがわかったので試した内容のメモ。
グループIDについてはDBに登録されていることが前提としている。
つまり登録されていないIDはエラー扱い。モデル名はGroupInformationとする。

1. クライアント側

こういう風にすればOKという情報しかなかった。

http://localhost:3000/auth/:provider?group_id=1

devise_token_authというよりはdeviseでのやり方だったので、正直怪しかったけど結局クライアント側としてはこれで問題はなかった。

2. サーバ側

以下のようにして対応する。(変更箇所のみ抜粋)

app/controllers/users/omniauth_callbacks_controller.rb
module Users
  class OmniauthCallbacksController < DeviseTokenAuth::OmniauthCallbacksController
    include Devise::Controllers::Rememberable
    before_action :group_id_valid?, only: [:omniauth_success]

    def redirect_callbacks
      session[:group_id] = request.env['omniauth.params']['group_id']
      super
    end

    def omniauth_success
      logger.debug(session[:group_id])
      # なんか処理
      session.delete(:group_id)
      super
    end
    # 省略

    private
    def group_id_valid?
      GroupInformation.find_by_id(session[:group_id]).nil?
    end
  end
end

最初はredirect_callbacksでparams['group_id']を使えば良いじゃんと思って試したけど、facebookやgoogleは無理だった。

3. 付加したグループIDのチェック

ミドルウェアで/auth/:providerにリクエストがきたときに、グループIDが付いていない場合は弾いたほうが良いんじゃないかなーとはおもっているんだけど、正直どのタイミングが良いのかわからん。

変にredirect_callbacksでグループIDを確認して弾く(認証処理を中断する)と
facebookでは「アカウントの安全確認」が発動してアカウントが一時的に凍結されてしまうことがある。
実際params['group_id']でグループIDが取れるのか試したときに、例外で認証処理が中断された結果、facebook側に不審なアクティビティ(だっけ?)と思われてしまい、アカウントが数日凍結された。おのれfacebook

なのでミドルウェアで弾いてしまうか、provider側の認証処理が終わってから確認するかどっちかになるんじゃないのかと。
どっちがいいんだろ?

上記の例では認証成功後に確認するようにしたけど、もしミドルウェアでチェックするならこんな感じ?

lib/omniauth/custom_middleware.rb
require 'rack'
module Omniauth
  class CustomMiddleware
    def initialize(app)
      @app = app
    end

    def call(env)
      status, headers, body = @app.call(env)
      request = ActionDispatch::Request.new(env)
      if request.fullpath.include?('/auth') && !request.fullpath.include?('/callback')
        if request.params.has_key?('group_id')
          if group_id_valid?(request.params['group_id'])
            status, headers, body = error_response(status, headers, no_registered_error)
          end
        else
          status, headers, body = error_response(status, headers, no_query_error)
        end
      end
      response = Rack::Response.new body, status, headers
      response.finish
    end

    private
    def error_response(status, headers, body)
      content_length = body.inject(0) do |sum, content|
        sum + content.bytesize
      end
      headers["Content-Length"] = content_length.to_s
      headers.delete_if {|key, val| key == "Location" }
      status = 400
      [status, headers, body]
    end

    def no_query_error
      ["<html><body>Group ID is not found. </body></html>"]
    end

    def no_registered_error
      ["<html><body>Group ID is not registered. </body></html>"]
    end

    def group_id_valid?(group_id)
      GroupInformation.find_by_id(group_id).nil?
    end
  end
end

group_idがついていなかったり、存在しないgroup_idが付加されているなら、400エラーを返すようにレスポンスを書き換える。そうでなければ何もしない(そのまま処理を続行)。

ActionDispatch::Requestや@app.call(env)を使わずにenvから自分で取り出してやったほうがいいのかなー。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0