Posted at

【Rails】RailsでAPIの簡単なトークン認証を実装する

More than 3 years have passed since last update.


準備

Rails 5のAPI modeでRails newする。

rails new apiTokenAuthentication --api -d postgresql

scaffoldする。てきとうなAPIを作る。

bundle exec rails g scaffold Product name:string age:integer email:string

bundle exec rake db:setup
bundle exec rake db:migrate

動作確認

$ curl -X POST -H 'Content-Type:application/json' -d '{ "name": "test", "price": 500 }' http://0.0.0.0:3000/products

$ curl -X GET -H 'Content-Type:application/json' http://0.0.0.0:3000/products | jq .

[
{
"updated_at": "2016-09-14T17:54:24.717Z",
"created_at": "2016-09-14T17:54:24.717Z",
"price": 500,
"name": "test",
"id": 1
}
]


トークン認証


authenticate_or_request_with_http_tokenを使う

authenticate_or_request_with_http_tokenにブロックを渡してトークンをチェックする。


app/controllers/application_controller.rb

class ApplicationController < ActionController::API

include ActionController::HttpAuthentication::Token::ControllerMethods

before_action :authenticate

protected
def authenticate
authenticate_or_request_with_http_token do |token, options|
token == 'FOO'
end
end
end


動作確認。AuthorizationヘッダーにAuthorization: Token FOOAuthorization: Bearer FOOがない場合は、HTTP Token: Access denied.を返すようになった。

$ curl -X GET -H 'Authorization: Token BAR' -H 'Content-Type:application/json' http://0.0.0.0:3000/products/1

HTTP Token: Access denied.

$ curl -X GET -H 'Authorization: Token FOO' -H 'Content-Type:application/json' http://0.0.0.0:3000/products/1 | jq .
{
"updated_at": "2016-09-14T17:54:24.717Z",
"created_at": "2016-09-14T17:54:24.717Z",
"price": 500,
"name": "test",
"id": 1
}


authenticate_with_http_tokenを使う

authenticate_with_http_tokenにブロックを渡してトークンをチェックする。

authenticate_or_request_with_http_tokenと違ってレスポンスを返す処理は自分で実装する。


app/controllers/application_controller.rb

class ApplicationController < ActionController::API

include ActionController::HttpAuthentication::Token::ControllerMethods

before_action :authenticate

protected
def authenticate
authenticate_token || render_unauthorized
end

def authenticate_token
authenticate_with_http_token do |token, options|
token == 'FOO'
end
end

def render_unauthorized
# render_errors(:unauthorized, ['invalid token'])
obj = { message: 'token invalid' }
render json: obj, status: :unauthorized
end
end


動作確認。

$ curl -X GET -H 'Authorization: Token BAR' -H 'Content-Type:application/json' http://0.0.0.0:3000/products/1 | jq .                                                                                   

{
"message": "token invalid"
}


まとめ

method

authenticate_with_http_token
トークンとオプションを受け取るブロックを渡してToken認証する。レスポンスは自分で書く。

request_http_token_authentication
中でauthenticate_with_http_tokenを使っていて、ブロックを渡すところまでは一緒。こちらは簡単なテキストのレスポンスを返すところまでやってくれるのでレスポンスの処理を書く必要がない。


注意

Rail5ではAuthorization: Token xxx, Authorization: Bearer xxxのようにTokenでもBearerでもどちらでもいける。

Rail4の場合は、Tokenの方しか使えないので注意。


参考


Rails5 APIモード

http://morizyun.github.io/blog/rails-api-5.0.0.beta.2/

https://www.hommax39.com/archives/170

http://totutotu.hatenablog.com/entry/2015/12/19/093944


トークン認証

http://sourcey.com/building-the-prefect-rails-5-api-only-app/#versioning-your-api

https://www.codeschool.com/blog/2014/02/03/token-based-authentication-rails/

http://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Token.html

http://techblog.thescore.com/2014/06/25/http-basic-authentication-and-http-token-authentication/

http://security.stackexchange.com/questions/108662/why-is-bearer-required-before-the-token-in-authorization-header-in-a-http-re

http://qiita.com/uasi/items/cfb60588daa18c2ec6f5

http://edgeapi.rubyonrails.org/classes/ActionController/HttpAuthentication/Token.html

http://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Token/ControllerMethods.html#method-i-authenticate_with_http_token