简体   繁体   中英

Always get JWTSessions::Errors::Unauthorized in Api::V1, nil JSON Token in Rails and jwt_sessions

I'm new to JWT authorization and have followed the boiler plate to set up auth in Rails. When I try to test my routes by calling localhost:5000/api/v1/users or any controller for that matter, I get the following everytime:

JWTSessions::Errors::Unauthorized in Api::V1

Nil JSON web token

Obviously a token isn't being generated but not sure how to create one from just checking controllers in Rails. Is there a way to do this with Postman?

Here are my relevant controllers:

Application Controller:


class ApplicationController < ActionController::API
    include JWTSessions::RailsAuthorization
    rescue_from JWTSessions::Errors::Unauthorized, with: :not_authorized


    private 

    def current_user
        @current_user ||= User.find(payload['user_id'])
    end

    def not_authorized
        render json: { error: 'Not authorized' }, status: :unauthorized 
    end


end

Signup:


 class SignupController < ApplicationController
  def create
    user = User.new(user_params)
    if user.save
      payload  = { user_id: user.id }
      session = JWTSessions::Session.new(payload: payload, refresh_by_access_allowed: true)
      tokens = session.login

      response.set_cookie(JWTSessions.access_cookie,
                          value: tokens[:access],
                          httponly: true,
                          secure: Rails.env.production?)
      render json: { csrf: tokens[:csrf] }
    else
      render json: { error: user.errors.full_messages.join(' ') }, status: :unprocessable_entity
    end
  end

  private

  def user_params
    params.permit(:first_name, :last_name, :username, :email, :password, :password_confirmation)
  end
end

UsersController:


class Api::V1::UsersController < ApplicationController
     before_action :find_user, only: [:update, :show, :destroy]

  def index
  @users = User.all
  render json: @users, status: :accepted
  end


  def create
    @user = User.new(user_params)

    if @user.save
      render json: {user: UserSerializer.new(@user), token: Rails.application.credentials.jwt}, status: :ok
    else
      render json: {errors: @user.errors.full_messages}
    end
  end


  def show
    if @user
      if curr_user.id == @user.id
        render json: @user
      else
        render json: {errors: @user.errors.full_messages }, status: :unprocessible_entity
      end
    else
      render json: {errors: "User not found!"}
    end
  end


  def update
    if curr_user.id == @user.id
      @user.update(user_params)
      if @user.save
      render json: @user, status: :accepted
      else
     render json: { errors: @user.errors.full_messages }, status: :unprocessible_entity
      end
    end
  end


  def destroy
    if curr_user.id == @user.id
      @user.delete
      render json: "user deleted", status: :ok
    else
      render json: { errors: "You are not authorized to delete"}
    end
  end

  private

  def user_params
   params.permit(:first_name, :last_name, :email, :username, :password_digest)
  end


  def find_user
   @user = User.find(params[:id])
  end



end

Routes

Rails.application.routes.draw do




  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html

  namespace :api do   
    namespace :v1 do   
      resources :users, only: [:index, :show, :create, :update, :destroy]
      resources :categories, only: [:index, :show, :create, :update, :destroy]
      resources :opportunities
      resources :opportuniy_api, only: [:index, :show]

    end
  end

  post 'refresh', controller: :refresh, action: :create
  post 'signin', controller: :signin, action: :create 
  post 'signup', controller: :signup, action: :create 
  delete 'signin', controller: :signin, action: :destroy 

end

It is showing up "Nil JSON Web Token" because rails is unable to find any authorization token in request.headers["Authorization"]. Going through the jwt_sessions readme file https://github.com/tuwukee/jwt_sessions you will find that "Headers must include Authorization: Bearer with access token." This is what you are missing in your case. Secondly, you don't need to use CSRF tokens in rails. As a Rails developer, you basically get CSRF protection for free. It starts with this single line in application_controller.rb, which enables CSRF protection:

protect_from_forgery with: :exception

I have tried the same and my code works fine:

Signup:

class SignupController < ApplicationController
  skip_before_action :verify_authenticity_token

    def create
        user = User.new(user_params)
        if user.save
            payload  = { user_id: user.id }
            session = JWTSessions::Session.new(payload: payload, refresh_by_access_allowed: true)
            tokens = session.login

            response.set_cookie(JWTSessions.access_cookie,
                                value: tokens[:access],
                                httponly: true,
                                secure: Rails.env.production?)
            render json: tokens
        else
            render json: { error: user.errors.full_messages.join(' ') }, status: :unprocessable_entity
        end
    end

    private

    def user_params
        params.permit(:username, :email, :password, :password_confirmation)
    end
  end

Or you can make it even simpler: Signup

class SignupController < ApplicationController
  def create
    user = User.new(user_params)
    if user.save
      payload  = { user_id: user.id }
      session = JWTSessions::Session.new(payload: payload, refresh_by_access_allowed: true)
      render json: session.login //or render json: session.login[:access]
    else
      render json: { error: user.errors.full_messages.join(' ') }, status: :unprocessable_entity
    end
  end

  private

  def user_params
    params.permit(:email, :password, :password_confirmation, :signup)
  end
end

application_controller:

class ApplicationController < ActionController::Base
    protect_from_forgery prepend: true, with: :exception
    include JWTSessions::RailsAuthorization 
    rescue_from JWTSessions::Errors::Unauthorized, with: :not_authorized

    def index
        render template: 'application'
    end

    private
    def current_user
        @current_user ||= User.find(payload['user_id'])
    end

    def not_authorized
        render json: { error: 'Not authorized' }, status: :unauthorized
    end
end

ajax call from frontend(vue) to rails: Inspect your token and you will get the access_token within it. Or render token[:access] from rails to frontend. Include this access token in the Header for every request you make to the rails api.

$.ajax({
            beforeSend: function(xhr) {
                xhr.setRequestHeader('Authorization', 'Bearer ' + <access_token>);
            },
            url: '/api/home'..

Hope this helps :)

I dit it, for me it worked

def current_user
  return unless request.headers.include? "Authorization"

  @current_user ||= User.find(payload['user_id'])
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM