実装方針
- 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を削除
挙動
感想
結局deviseのコントローラー0から改造することになってしまった。
まだ処理内容わかっていない点も多いのでこの後コメントアウトをつける作業に移る。
参考
devise-auth-token公式
https://github.com/lynndylanhurley/devise_token_auth/blob/master/app/controllers/devise_token_auth/sessions_controller.rb
次やること
- 結合テスト
- コメントアウトつける
- react-routerの導入