LoginSignup
1
1

More than 3 years have passed since last update.

【Rails】Reactとaxiosを用いて非同期でdevise-auth-tokenを利用したのサインアウトを行う

Last updated at Posted at 2021-03-20

実装方針

  • devise-auth-tokenで使用する、uid, client, access-tokenの3つが全て存在する場合のみサインアウトする
  • csrf-tokenのチェックを事前に行う
  • client, tokenをdestroyアクション内で削除
  • csrf-token,sessionをafter_actionで削除

フロントエンド

リクエストの送信

getCsrfToken() {
    if (!(axios.defaults.headers.common['X-CSRF-Token'])) {
      return (
        document.getElementsByName('csrf-token')[0].getAttribute('content')
      )
    } else {
      return (
        axios.defaults.headers.common['X-CSRF-Token']
      )
    }
  };


setAxiosDefaults() {
    axios.defaults.headers.common['X-CSRF-Token'] = this.getCsrfToken();
  };

userAuthentification() {
    if (axios.defaults.headers.common['uid'] && axios.defaults.headers.common['client'] && axios.defaults.headers.common['access-token']) {
      axios.defaults.headers.common['uid']
      axios.defaults.headers.common['client']
      axios.defaults.headers.common['access-token']
    } else {
      return null
    }
  }


if (this.props.content == 'SignOut') {
      this.setAxiosDefaults();
      this.userAuthentification()
      axios
      .delete('/api/v1/users/sign_out', {uid: axios.defaults.headers.common['uid']})
  this.setAxiosDefaults();
  this.userAuthentification()

この2行でそれぞれcsrf-tokenとuser情報をrequest.headersにセットする。後者は新規登録時に発行される情報で、devise-auth-tokenを用いると発行されるもの。

def update_auth_header 
    @token = @user.create_token
    return unless @user && @token.client
    @token.client = nil unless @used_auth_by_token
    if @used_auth_by_token && !DeviseTokenAuth.change_headers_on_each_request
      auth_header = @user.build_auth_header(@token.token, @token.client)
      response.headers.merge!(auth_header)  
    else
      unless @user.reload.valid?
        @user = @user.class.find(@user.to_param) 
        unless @user.valid?
          raise DeviseTokenAuth::Errors::InvalidModel, "Cannot set auth token in invalid model. Errors: #{@resource.errors.full_messages}"
        end
      end
      refresh_headers
    end
  end

これを新規登録後に読み込むことで request.headerにclient、tokenをmerge。uidはデフォルトでresponse.headersに含まれている。

      .delete('/api/v1/users/sign_out', {uid: axios.defaults.headers.common['uid']})

ここは普段どおりのaxiosのリクエスト。パラメータにはuserの識別子となるuidを渡す。

サーバーサイド

def destroy  
  @user = User.find_for_database_authentication(uid: request.headers['uid'])
  @token = request.headers['access-token']
  @client = request.headers['client']
  if @user && @client && @token
    @token.clear 
    @client = nil
    render_destroy_success
  else
    render_destroy_error
  end
end

リクエストヘッダーからuid(email)を取り出してインスタンスをDBから参照し、token、clientもそれぞれリクエストヘッダーから定義する。
user,token,client全てが存在しないとログアウトできないようにしている。
次にtokenとclientを削除することでクライアント側でuserが存在しない状態にし、ログアウト処理完了。

destroyアクション後にafter_actionで以下を読み込む

after_action :set_csrf_token_header
after_action :reset_session, only: [:destroy]

これでcsrf-tokenとsessionを削除

挙動

recommended-books-2-2.gif

感想

結局deviseのコントローラー0から改造することになってしまった。
まだ処理内容わかっていない点も多いのでこの後コメントアウトをつける作業に移る。

参考

devise-auth-token公式
https://github.com/lynndylanhurley/devise_token_auth/blob/master/app/controllers/devise_token_auth/sessions_controller.rb

次やること

  • 結合テスト
  • コメントアウトつける
  • react-routerの導入
1
1
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
1
1