我以this系列作为工作包网站的Rails后端的起点。对其进行改编通常非常简单,并且可以按照我想要的去做。一个大问题是,“ index”和“ show”(读操作)应该在没有身份验证的情况下可用,而“ create”,“ update”和“ delete”(写操作)则需要有效的JWT。
按照用于从身份验证中排除注册和登录路由的方法,我尝试了
skip_before_action :authorize_request, only: [:index, :show]
在适当的控制器中。但是,这会导致应用程序崩溃,
NoMethodError (undefined method `works' for nil:NilClass):
app/controllers/works_controller.rb:10:in `index'
问题似乎很明显-如果跳过身份验证操作,则不会实例化该类-至少对于我而言,此修复没有。谁能帮忙吗?
该项目的代码为here。
应用程序控制器
class ApplicationController < ActionController::API
include Response
include ExceptionHandler
# called before every action on controllers
before_action :authorize_request
attr_reader :current_user
private
# Check for valid request token and return user
def authorize_request
@current_user = (AuthorizeApiRequest.new(request.headers).call)[:user]
end
end
“ Works”控制器
class WorksController < ApplicationController
#skip_before_action :authorize_request, only: [:index, :show]
before_action :set_work, only: [:show, :update, :destroy]
# GET /works
def index
@works = current_user.works
json_response(@works)
end
# POST /works
def create
@work = current_user.works.create!(work_params)
json_response(@work, :created)
end
# GET /works/:id
def show
json_response(@work)
end
# PUT /works/:id
def update
@work.update(work_params)
head :no_content
end
# DELETE /works/:id
def destroy
@work.destroy
head :no_content
end
private
def work_params
# whitelist params
params.permit(:title, :nature, :role, :client, :timeframe, :description, :images, :url, :blog_post)
end
def set_work
@work = Work.find(params[:id])
end
end
“用户”控制器
class UsersController < ApplicationController
skip_before_action :authorize_request, only: :create
def create
user = User.create!(user_params)
auth_token = AuthenticateUser.new(user.username, user.password).call
response = { message: Message.account_created, access_token: auth_token }
json_response(response, :created)
end
def show
json_response(username: current_user.username)
end
private
def user_params
params.permit(
:username,
:password,
:password_confirmation
)
end
end
“身份验证”控制器
class AuthenticationController < ApplicationController
skip_before_action :authorize_request, only: :authenticate
# return auth token once user is authenticated
def authenticate
auth_token =
AuthenticateUser.new(auth_params[:username], auth_params[:password]).call
json_response(access_token: auth_token)
end
private
def auth_params
params.permit(:username, :password)
end
end
“ AuthenticateUser”助手
class AuthenticateUser
def initialize(username, password)
@username = username
@password = password
end
# Service entry point
def call
JsonWebToken.encode(user_id: user.id) if user
end
private
attr_reader :username, :password
# verify user credentials
def user
user = User.find_by(username: username)
return user if user && user.authenticate(password)
# raise Authentication error if credentials are invalid
raise(ExceptionHandler::AuthenticationError, Message.invalid_credentials)
end
end
“ AuthorizeApiRequest”助手
class AuthorizeApiRequest
def initialize(headers = {})
@headers = headers
end
# Service entry point - return valid user object
def call
{
user: user
}
end
private
attr_reader :headers
def user
# check if user is in the database
# memoize user object
@user ||= User.find(decoded_auth_token[:user_id]) if decoded_auth_token
# handle user not found
rescue ActiveRecord::RecordNotFound => e
# raise custom error
raise(
ExceptionHandler::InvalidToken,
("#{Message.invalid_token} #{e.message}")
)
end
# decode authentication token
def decoded_auth_token
@decoded_auth_token ||= JsonWebToken.decode(http_auth_header)
end
# check for token in `Authorization` header
def http_auth_header
if headers['Authorization'].present?
return headers['Authorization'].split(' ').last
end
raise(ExceptionHandler::MissingToken, Message.missing_token)
end
end
“ ExceptionHandler”帮助器
module ExceptionHandler
extend ActiveSupport::Concern
# Define custom error subclasses - rescue catches `StandardErrors`
class AuthenticationError < StandardError; end
class MissingToken < StandardError; end
class InvalidToken < StandardError; end
included do
# Define custom handlers
rescue_from ActiveRecord::RecordInvalid, with: :four_twenty_two
rescue_from ExceptionHandler::AuthenticationError, with: :unauthorized_request
rescue_from ExceptionHandler::MissingToken, with: :four_twenty_two
rescue_from ExceptionHandler::InvalidToken, with: :four_twenty_two
rescue_from ActiveRecord::RecordNotFound do |e|
json_response({ message: e.message }, :not_found)
end
end
private
# JSON response with message; Status code 422 - unprocessable entity
def four_twenty_two(e)
json_response({ message: e.message }, :unprocessable_entity)
end
# JSON response with message; Status code 401 - Unauthorized
def unauthorized_request(e)
json_response({ message: e.message }, :unauthorized)
end
end
答案 0 :(得分:1)
错误消息指出:
NoMethodError (undefined method `works' for nil:NilClass):
app/controllers/works_controller.rb:10:in `index'
或者要翻译它,在works_controller.rb文件的第10行上,我们在works
上调用了一个名为nil
的方法,这会引发错误。
假设works_controller的第10行是
@works = current_user.works
然后错误消息告诉我们,我们在nil上调用works
,即我们没有current_user
。
您在分配此代码的地方均无法正常工作,或者您正在登录的这部分代码未登录且未对此进行编码。无论哪种方式,current_user
变量都将返回nil,并且不应返回。