Rails API With Authentication Simple Tutorial

0.1 2016.03.28 22:50* 字数 278


Add the following to your Gemfile:

gem 'devise_token_auth'
gem 'devise', '~> 4.0.0.rc1'

Then install the gem using bundle:

bundle install

Creating User Model and Migration

Next, let's create a model for authentication.

rails g devise_token_auth:install User auth

It will return such things at console:

Running via Spring preloader in process 78994
      create  config/initializers/devise_token_auth.rb
      create  db/migrate/20160328130022_devise_token_auth_create_users.rb
      create  app/models/user.rb
      insert  app/controllers/application_controller.rb
        gsub  config/routes.rb

Since we don't need omniauth at the moment, we should remove the configure(:omniauthable) in model:

class User < ActiveRecord::Base
  # Include default devise modules.
  devise :database_authenticatable, :registerable,
          :recoverable, :rememberable, :trackable, :validatable,
  include DeviseTokenAuth::Concerns::User

Migration comes next!

rake db:migrate

We may get an error while using devise that version is lower that 4.0.0:

DEPRECATION WARNING: alias_method_chain is deprecated. Please, use Module#prepend instead.....
NameError: uninitialized constant ActionController::RackDelegation...


Run this command to show all routes:

rake routes

The result is:

Prefix Verb URI Pattern Controller#Action
new_user_session GET /auth/sign_in(.:format) devise_token_auth/sessions#new
user_session POST /auth/sign_in(.:format) devise_token_auth/sessions#create
destroy_user_session DELETE /auth/sign_out(.:format) devise_token_auth/sessions#destroy
user_password POST /auth/password(.:format) devise_token_auth/passwords#create
new_user_password GET /auth/password/new(.:format) devise_token_auth/passwords#new
edit_user_password GET /auth/password/edit(.:format) devise_token_auth/passwords#edit
PATCH /auth/password(.:format) devise_token_auth/passwords#update
PUT /auth/password(.:format) devise_token_auth/passwords#update
cancel_user_registration GET /auth/cancel(.:format) devise_token_auth/registrations#cancel
user_registration POST /auth(.:format) devise_token_auth/registrations#create
new_user_registration GET /auth/sign_up(.:format) devise_token_auth/registrations#new
edit_user_registration GET /auth/edit(.:format) devise_token_auth/registrations#edit
PATCH /auth(.:format) devise_token_auth/registrations#update
PUT /auth(.:format) devise_token_auth/registrations#update
DELETE /auth(.:format) devise_token_auth/registrations#destroy
user_confirmation POST /auth/confirmation(.:format) devise_token_auth/confirmations#create
new_user_confirmation GET /auth/confirmation/new(.:format) devise_token_auth/confirmations#new
GET /auth/confirmation(.:format) devise_token_auth/confirmations#show
auth_validate_token GET /auth/validate_token(.:format) devise_token_auth/token_validations#validate_token

As shown above, /auth includes all the action related to authentication.


Let's create a Listing model to show how it works.

rails g scaffold listing content:text title:string

After migration, add one line code to application_controller.rb

class ListingsController < ApplicationController
  before_action :authenticate_user!

All right, you should get 401 while visit http://localhost:3000/listings/1.

Sign up

Firstly, wo don't need users confirm their registration with their own email, so we remove :confirmable in models/user.rb.

Sending a post requset to http://localhost:3000/auth with the parameters(email, password, password_confirmation) would create a user.

curl -X POST -H "Cache-Control: no-cache" -H "Postman-Token: 3a9aa5e9-2ba7-7de3-66b4-ec3a85f6ddd0" "http://localhost:3000/auth?email=zhen6939@163.com&password=51190109&password_confirmation=51190109"

Sign in

According to the routes sheet, implement 'sign in' needs a post request to */auth/sign_in *:

curl -X POST -H "Cache-Control: no-cache" -H "Postman-Token: 2c7e777b-031d-c958-79e7-04ef75fe9bd5" "http://localhost:3000//auth/sign_in?email=zhen6939@163.com&password=51190109"

It returns access-token, client, expiry, token-type, uid.

param description
access-token This serves as the user's password for each request. A hashed version of this value is stored in the database for later comparison. This value should be changed on each request.
client This enables the use of multiple simultaneous sessions on different clients. (For example, a user may want to be authenticated on both their phone and their laptop at the same time.)
expiry The date at which the current session will expire. This can be used by clients to invalidate expired tokens without the need for an API request.
uid A unique value that is used to identify the user. This is necessary because searching the DB for users by their access token will make the API susceptible to timing attacks.

Using those params properly, we can kindly keep user login at different devices.

How the authentication works

As shown above, access-token is used as 'password' for each request. By default, It should be changed after every request to server. At other words, every response of request to server will return different access-token. It means that every request you sent should include access-token which you got at previous request.

Web note ad 1