- add following into Gemfile
# Use Json Web Token (JWT) for token based authentication
gem 'jwt'
# Use ActiveModel has_secure_password
gem 'bcrypt', '~> 3.1.7'
bundle install
- update routes
# config/routes.rb
Rails.application.routes.draw do
resources :users, param: :_username
post '/auth/login', to: 'authentication#login'
get '/*a', to: 'application#not_found'
end
- Create JsonWebToken class (app/lib/json_web_token.rb)
class JsonWebToken
SECRET_KEY = Rails.application.secrets.secret_key_base. to_s
def self.encode(payload, exp = 24.hours.from_now)
payload[:exp] = exp.to_i
JWT.encode(payload, SECRET_KEY)
end
def self.decode(token)
decoded = JWT.decode(token, SECRET_KEY)[0]
HashWithIndifferentAccess.new decoded
end
end
- Create authorize_request function (app/controllers/application_controller.rb)
class ApplicationController < ActionController::API
def not_found
render json: { error: 'not_found' }
end
def authorize_request
header = request.headers['Authorization']
header = header.split(' ').last if header
begin
@decoded = JsonWebToken.decode(header)
@current_user = User.find(@decoded[:user_id])
rescue ActiveRecord::RecordNotFound => e
render json: { errors: e.message }, status: :unauthorized
rescue JWT::DecodeError => e
render json: { errors: e.message }, status: :unauthorized
end
end
end
- Create user model (
rails g model user name:string username:string email:string password_digest:string
) (remembder to db:setup database first) - add user validation (app/models/user.rb)
class User < ApplicationRecord
has_secure_password
validates :email, presence: true, uniqueness: true
validates :email, format: { with: URI::MailTo::EMAIL_REGEXP }
validates :username, presence: true, uniqueness: true
validates :password,
length: { minimum: 6 },
if: -> { new_record? || !password.nil? }
end
- Create user controller
rails g controller users
class UsersController < ApplicationController
before_action :authorize_request, except: :create
before_action :find_user, except: %i[create index]
# GET /users
def index
@users = User.all
render json: @users, status: :ok
end
# GET /users/{username}
def show
render json: @user, status: :ok
end
# POST /users
def create
@user = User.new(user_params)
if @user.save
render json: @user, status: :created
else
render json: { errors: @user.errors.full_messages },
status: :unprocessable_entity
end
end
# PUT /users/{username}
def update
unless @user.update(user_params)
render json: { errors: @user.errors.full_messages },
status: :unprocessable_entity
end
end
# DELETE /users/{username}
def destroy
@user.destroy
end
private
def find_user
@user = User.find_by_username!(params[:_username])
rescue ActiveRecord::RecordNotFound
render json: { errors: 'User not found' }, status: :not_found
end
def user_params
params.permit(
:name, :username, :email, :password, :password_confirmation
)
end
end
- Create authentication controller
rails g controller authentication
class AuthenticationController < ApplicationController
before_action :authorize_request, except: :login
# POST /auth/login
def login
@user = User.find_by_email(params[:email])
if @user&.authenticate(params[:password])
token = JsonWebToken.encode(user_id: @user.id)
time = Time.now + 24.hours.to_i
render json: { token: token, exp: time.strftime("%m-%d-%Y %H:%M"),
username: @user.username }, status: :ok
else
render json: { error: 'unauthorized' }, status: :unauthorized
end
end
private
def login_params
params.permit(:email, :password)
end
end
- Migrate database (
rails db:migrate
)
- http://localhost:3000/users - POST(name, username, email, password)
- http://loachost:3000/auth/login - POST(email, password)
- http://locahost:3000/users - GET (Auth Token)
- http://locahost:3000/users/ - GET (Auth Token)
This README would normally document whatever steps are necessary to get the application up and running.
Things you may want to cover:
-
Ruby version
-
System dependencies
-
Configuration
-
Database creation
-
Database initialization
-
How to run the test suite
-
Services (job queues, cache servers, search engines, etc.)
-
Deployment instructions
-
...