From 960fea0216364542eeb433a508f79e3de4724629 Mon Sep 17 00:00:00 2001 From: LucDelmon Date: Tue, 23 Aug 2022 15:11:46 +0200 Subject: [PATCH] feat: add authentication controller --- app/controllers/authentication_controller.rb | 26 +++++++++++ config/routes.rb | 1 + spec/requests/authentication_spec.rb | 48 ++++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 app/controllers/authentication_controller.rb create mode 100644 spec/requests/authentication_spec.rb diff --git a/app/controllers/authentication_controller.rb b/app/controllers/authentication_controller.rb new file mode 100644 index 0000000..e6d50a6 --- /dev/null +++ b/app/controllers/authentication_controller.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +class AuthenticationController < ApplicationController + skip_before_action :authorize_request, only: :login + + # POST /auth/login + # @return [JSON, nil] + def login + @user = User.find_by(email: params[:email]) + if @user&.authenticate(params[:password]) + exp = 24.hours.from_now + + token = JsonWebToken.encode(user_id: @user.id, exp: exp.to_i) + render json: { token: token, exp: exp.strftime('%m-%d-%Y %H:%M') }, status: :ok + else + render json: { error: 'unauthorized' }, status: :unauthorized + end + end + + private + + # @return [ActionController::Parameters] + def login_params + params.permit(:email, :password) + end +end diff --git a/config/routes.rb b/config/routes.rb index 67b853e..8f7bc8d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -4,6 +4,7 @@ Rails.application.routes.draw do mount Sidekiq::Web => '/sidekiq' resources :users + post '/auth/login', to: 'authentication#login' resources :authors resources :books # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html diff --git a/spec/requests/authentication_spec.rb b/spec/requests/authentication_spec.rb new file mode 100644 index 0000000..82f0d68 --- /dev/null +++ b/spec/requests/authentication_spec.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Authentications', type: :request do + describe 'POST auth/login' do + let!(:user) { User.create(email: 'jean@gmail.com', password: 'password') } + let(:request_type) { :post } + let(:request_url) { auth_login_url } + let(:freeze_time) { Time.current } + + before do + allow(JsonWebToken).to receive(:encode).and_return('token') + end + + context 'with valid params' do + before { @params = { email: user.email, password: 'password' } } + + it 'authenticates the user and return a jwt token for the user' do + Timecop.freeze(freeze_time) { request } + expect(JsonWebToken).to have_received(:encode).with(user_id: user.id, exp: (freeze_time + 24.hours).to_i) + expect(JSON.parse(response.body)).to eq( + { 'token' => 'token', 'exp' => (freeze_time + 24.hours).strftime('%m-%d-%Y %H:%M') } + ) + end + end + + shared_examples_for 'a request returning unauthorized' do + it 'returns an unauthorized error' do + request + expect(response).to have_http_status(:unauthorized) + expect(JSON.parse(response.body)).to eq({ 'error' => 'unauthorized' }) + end + end + + context 'when user does not exist' do + before { @params = { email: 'error@gmail.com', password: 'password' } } + + it_behaves_like 'a request returning unauthorized' + end + + context 'when password is invalid' do + before { @params = { email: user.email, password: 'error' } } + + it_behaves_like 'a request returning unauthorized' + end + end +end