Ruby on rails CanCanCan不允许访问返回所有记录的端点
我正在尝试为我在Rails中构建的API配置授权。授权似乎有效,但在返回资源所有记录的端点上无效。这些端点也恰好是在Ruby on rails CanCanCan不允许访问返回所有记录的端点,ruby-on-rails,cancancan,rolify,Ruby On Rails,Cancancan,Rolify,我正在尝试为我在Rails中构建的API配置授权。授权似乎有效,但在返回资源所有记录的端点上无效。这些端点也恰好是在config/routes.rb中的资源块外部创建的(不确定这是否是正确的解释方法) 例如:当我转到以下端点时,如果有数据,我会得到200 HTTP响应;如果记录不存在,我会得到204 HTTP响应: http://localhost:3000/v1/resources/venues/zoom 但当我转到以下端点时,我得到一个授权错误: http://localhost:3000
config/routes.rb
中的资源块外部创建的(不确定这是否是正确的解释方法)
例如:当我转到以下端点时,如果有数据,我会得到200 HTTP响应;如果记录不存在,我会得到204 HTTP响应:
http://localhost:3000/v1/resources/venues/zoom
但当我转到以下端点时,我得到一个授权错误:
http://localhost:3000/v1/resources/venues/all
这是我的config/routes.rb
文件:
Rails.application.routes.draw do
# Private Messaging
resources :conversations, only: [:index, :create]
resources :messages, only: [:create]
mount ActionCable.server => '/cable'
# Admin
mount RailsAdmin::Engine => '/admin', as: 'rails_admin'
namespace :v1 do
namespace :resources do
# Users
post '/users/:id/avatar/upload' => 'users#upload_avatar'
patch '/users/:id/avatar/update' => 'users#update_avatar'
put '/users/:id/avatar/update' => 'users#update_avatar'
delete '/users/:id/avatar/delete' => 'users#delete_avatar'
namespace :users do
get ':id' => :show
end
# Venue Types
get '/venue_types/all' => 'venue_types#all'
post '/venues/:name/images/upload' => 'venues#upload_images'
namespace :venue_types do
get ':name' => :show
patch ':name' => :update
put ':name' => :update
delete ':name' => :delete
post 'new'
end
# Attributes
get '/attribute_defaults/all' => 'attribute_defaults#all'
namespace :attribute_defaults do
get ':id' => :show
patch ':id' => :update
put ':id' => :update
delete ':id' => :delete
post 'new'
end
# Venues
get '/venues/all' => 'venues#all'
namespace :venues do
get ':name' => :show
patch ':name' => :update
put ':name' => :update
delete ':name' => :delete
post 'new'
end
# Venue Attributes
get '/venue_attributes/all' => 'venue_attributes#all'
namespace :venue_attributes do
get ':id' => :show
patch ':id' => :update
put ':id' => :update
delete ':id' => :delete
post 'new'
end
# Bids
get '/bids/all' => 'bids#all'
namespace :bids do
get ':id' => :show
patch ':id' => :update
put ':id' => :update
delete ':id' => :delete
post 'new'
end
# Bookings
get '/bookings/all' => 'bookings#all'
namespace :bookings do
get ':id' => :show
patch ':id' => :update
put ':id' => :update
delete ':id' => :delete
post 'new'
end
# Venue Ratings
get '/venue_ratings/all' => 'venue_ratings#all'
namespace :venue_ratings do
get ':id' => :show
patch ':id' => :update
put ':id' => :update
delete ':id' => :delete
post 'new'
end
# User Ratings
get '/user_ratings/all' => 'user_ratings#all'
namespace :user_ratings do
get ':id' => :show
patch ':id' => :update
put ':id' => :update
delete ':id' => :delete
post 'new'
end
end
end
# Auth
devise_for :users,
path: 'auth',
path_names: {
sign_in: 'login',
sign_out: 'logout',
registration: 'register'
},
controllers: {
sessions: 'sessions',
registrations: 'registrations',
confirmations: 'confirmations'
}
end
# frozen_string_literal: true
class Ability
include CanCan::Ability
def initialize(user)
# Admin
if user.present? && user.is_admin?
can :manage, :all
# Host
elsif user.present? && user.is_host?
can :manage, User, id: user.id
can [:read, :write, :update], [Venue, VenueAttribute, Bid, UserRating, VenueRating]
can [:read], User
can :destroy, [Venue, VenueAttribute]
# Guest
elsif user.present? && user.is_guest?
can :manage, User, id: user.id
can [:write, :update], [Bid, VenueRating], id: user.id
can [:write, :update], [UserRating], rated_by: user.id
can :read, Bid, id: user.id
can :read, [Venue, User, VenueRating, UserRating]
# No role
else
can :read, [Venue, User, UserRating, VenueRating]
end
end
end
class V1::Resources::VenuesController < ActionController::API
load_and_authorize_resource param_method: :venue_params
respond_to :json
before_action :authenticate_user!, except: [:all, :show]
before_action :set_venue, except: [:all, :new]
# GET /v1/resources/venues/all
def all
@venues = Venue.all.where(is_published: true, is_expired: false)
if !@venues.empty?
render json: @venues, methods: :image_urls, status: :ok
else
head :no_content
end
end
# POST /v1/resources/venues/new
def new
@venue = Venue.new(venue_params)
if @venue.save
render json: @venue, status: :created
else
render json: @venue.errors, status: :unprocessable_entity
end
end
# GET /v1/resources/venues/:name
def show
if @venue
render json: @venue, methods: :image_urls, status: :ok
else
head :no_content
end
end
# PATCH/PUT /v1/resources/venues/:name
def update
if @venue.update(venue_params)
render json: @venue, status: :ok
else
render json: @venue.errors, status: :unprocessable_entity
end
end
# DELETE /v1/resources/venues/:name
def delete
@venue.destroy
head :no_content
end
# POST /v1/resources/venues/:name/images/upload
def upload_images
@venue.images.attach(params[:images])
render json: @venue, methods: :image_urls, status: :ok
end
private
# Use callbacks to share common setup or constraints between actions.
def set_venue
@venue = Venue.find_by(name: params[:name])
end
# Never trust parameters from the scary internet, only allow the white list through.
def venue_params
params.require(:venue).permit(:name, :price, :minimum_bid, :is_published, :currency, :is_expired, :location, :venue_type_id, :user_id, images: [])
end
end
这是我的app/models/ability.rb
文件:
Rails.application.routes.draw do
# Private Messaging
resources :conversations, only: [:index, :create]
resources :messages, only: [:create]
mount ActionCable.server => '/cable'
# Admin
mount RailsAdmin::Engine => '/admin', as: 'rails_admin'
namespace :v1 do
namespace :resources do
# Users
post '/users/:id/avatar/upload' => 'users#upload_avatar'
patch '/users/:id/avatar/update' => 'users#update_avatar'
put '/users/:id/avatar/update' => 'users#update_avatar'
delete '/users/:id/avatar/delete' => 'users#delete_avatar'
namespace :users do
get ':id' => :show
end
# Venue Types
get '/venue_types/all' => 'venue_types#all'
post '/venues/:name/images/upload' => 'venues#upload_images'
namespace :venue_types do
get ':name' => :show
patch ':name' => :update
put ':name' => :update
delete ':name' => :delete
post 'new'
end
# Attributes
get '/attribute_defaults/all' => 'attribute_defaults#all'
namespace :attribute_defaults do
get ':id' => :show
patch ':id' => :update
put ':id' => :update
delete ':id' => :delete
post 'new'
end
# Venues
get '/venues/all' => 'venues#all'
namespace :venues do
get ':name' => :show
patch ':name' => :update
put ':name' => :update
delete ':name' => :delete
post 'new'
end
# Venue Attributes
get '/venue_attributes/all' => 'venue_attributes#all'
namespace :venue_attributes do
get ':id' => :show
patch ':id' => :update
put ':id' => :update
delete ':id' => :delete
post 'new'
end
# Bids
get '/bids/all' => 'bids#all'
namespace :bids do
get ':id' => :show
patch ':id' => :update
put ':id' => :update
delete ':id' => :delete
post 'new'
end
# Bookings
get '/bookings/all' => 'bookings#all'
namespace :bookings do
get ':id' => :show
patch ':id' => :update
put ':id' => :update
delete ':id' => :delete
post 'new'
end
# Venue Ratings
get '/venue_ratings/all' => 'venue_ratings#all'
namespace :venue_ratings do
get ':id' => :show
patch ':id' => :update
put ':id' => :update
delete ':id' => :delete
post 'new'
end
# User Ratings
get '/user_ratings/all' => 'user_ratings#all'
namespace :user_ratings do
get ':id' => :show
patch ':id' => :update
put ':id' => :update
delete ':id' => :delete
post 'new'
end
end
end
# Auth
devise_for :users,
path: 'auth',
path_names: {
sign_in: 'login',
sign_out: 'logout',
registration: 'register'
},
controllers: {
sessions: 'sessions',
registrations: 'registrations',
confirmations: 'confirmations'
}
end
# frozen_string_literal: true
class Ability
include CanCan::Ability
def initialize(user)
# Admin
if user.present? && user.is_admin?
can :manage, :all
# Host
elsif user.present? && user.is_host?
can :manage, User, id: user.id
can [:read, :write, :update], [Venue, VenueAttribute, Bid, UserRating, VenueRating]
can [:read], User
can :destroy, [Venue, VenueAttribute]
# Guest
elsif user.present? && user.is_guest?
can :manage, User, id: user.id
can [:write, :update], [Bid, VenueRating], id: user.id
can [:write, :update], [UserRating], rated_by: user.id
can :read, Bid, id: user.id
can :read, [Venue, User, VenueRating, UserRating]
# No role
else
can :read, [Venue, User, UserRating, VenueRating]
end
end
end
class V1::Resources::VenuesController < ActionController::API
load_and_authorize_resource param_method: :venue_params
respond_to :json
before_action :authenticate_user!, except: [:all, :show]
before_action :set_venue, except: [:all, :new]
# GET /v1/resources/venues/all
def all
@venues = Venue.all.where(is_published: true, is_expired: false)
if !@venues.empty?
render json: @venues, methods: :image_urls, status: :ok
else
head :no_content
end
end
# POST /v1/resources/venues/new
def new
@venue = Venue.new(venue_params)
if @venue.save
render json: @venue, status: :created
else
render json: @venue.errors, status: :unprocessable_entity
end
end
# GET /v1/resources/venues/:name
def show
if @venue
render json: @venue, methods: :image_urls, status: :ok
else
head :no_content
end
end
# PATCH/PUT /v1/resources/venues/:name
def update
if @venue.update(venue_params)
render json: @venue, status: :ok
else
render json: @venue.errors, status: :unprocessable_entity
end
end
# DELETE /v1/resources/venues/:name
def delete
@venue.destroy
head :no_content
end
# POST /v1/resources/venues/:name/images/upload
def upload_images
@venue.images.attach(params[:images])
render json: @venue, methods: :image_urls, status: :ok
end
private
# Use callbacks to share common setup or constraints between actions.
def set_venue
@venue = Venue.find_by(name: params[:name])
end
# Never trust parameters from the scary internet, only allow the white list through.
def venue_params
params.require(:venue).permit(:name, :price, :minimum_bid, :is_published, :currency, :is_expired, :location, :venue_type_id, :user_id, images: [])
end
end
这是我的app/controllers/v1/resources/vinces\u controller.rb
文件:
Rails.application.routes.draw do
# Private Messaging
resources :conversations, only: [:index, :create]
resources :messages, only: [:create]
mount ActionCable.server => '/cable'
# Admin
mount RailsAdmin::Engine => '/admin', as: 'rails_admin'
namespace :v1 do
namespace :resources do
# Users
post '/users/:id/avatar/upload' => 'users#upload_avatar'
patch '/users/:id/avatar/update' => 'users#update_avatar'
put '/users/:id/avatar/update' => 'users#update_avatar'
delete '/users/:id/avatar/delete' => 'users#delete_avatar'
namespace :users do
get ':id' => :show
end
# Venue Types
get '/venue_types/all' => 'venue_types#all'
post '/venues/:name/images/upload' => 'venues#upload_images'
namespace :venue_types do
get ':name' => :show
patch ':name' => :update
put ':name' => :update
delete ':name' => :delete
post 'new'
end
# Attributes
get '/attribute_defaults/all' => 'attribute_defaults#all'
namespace :attribute_defaults do
get ':id' => :show
patch ':id' => :update
put ':id' => :update
delete ':id' => :delete
post 'new'
end
# Venues
get '/venues/all' => 'venues#all'
namespace :venues do
get ':name' => :show
patch ':name' => :update
put ':name' => :update
delete ':name' => :delete
post 'new'
end
# Venue Attributes
get '/venue_attributes/all' => 'venue_attributes#all'
namespace :venue_attributes do
get ':id' => :show
patch ':id' => :update
put ':id' => :update
delete ':id' => :delete
post 'new'
end
# Bids
get '/bids/all' => 'bids#all'
namespace :bids do
get ':id' => :show
patch ':id' => :update
put ':id' => :update
delete ':id' => :delete
post 'new'
end
# Bookings
get '/bookings/all' => 'bookings#all'
namespace :bookings do
get ':id' => :show
patch ':id' => :update
put ':id' => :update
delete ':id' => :delete
post 'new'
end
# Venue Ratings
get '/venue_ratings/all' => 'venue_ratings#all'
namespace :venue_ratings do
get ':id' => :show
patch ':id' => :update
put ':id' => :update
delete ':id' => :delete
post 'new'
end
# User Ratings
get '/user_ratings/all' => 'user_ratings#all'
namespace :user_ratings do
get ':id' => :show
patch ':id' => :update
put ':id' => :update
delete ':id' => :delete
post 'new'
end
end
end
# Auth
devise_for :users,
path: 'auth',
path_names: {
sign_in: 'login',
sign_out: 'logout',
registration: 'register'
},
controllers: {
sessions: 'sessions',
registrations: 'registrations',
confirmations: 'confirmations'
}
end
# frozen_string_literal: true
class Ability
include CanCan::Ability
def initialize(user)
# Admin
if user.present? && user.is_admin?
can :manage, :all
# Host
elsif user.present? && user.is_host?
can :manage, User, id: user.id
can [:read, :write, :update], [Venue, VenueAttribute, Bid, UserRating, VenueRating]
can [:read], User
can :destroy, [Venue, VenueAttribute]
# Guest
elsif user.present? && user.is_guest?
can :manage, User, id: user.id
can [:write, :update], [Bid, VenueRating], id: user.id
can [:write, :update], [UserRating], rated_by: user.id
can :read, Bid, id: user.id
can :read, [Venue, User, VenueRating, UserRating]
# No role
else
can :read, [Venue, User, UserRating, VenueRating]
end
end
end
class V1::Resources::VenuesController < ActionController::API
load_and_authorize_resource param_method: :venue_params
respond_to :json
before_action :authenticate_user!, except: [:all, :show]
before_action :set_venue, except: [:all, :new]
# GET /v1/resources/venues/all
def all
@venues = Venue.all.where(is_published: true, is_expired: false)
if !@venues.empty?
render json: @venues, methods: :image_urls, status: :ok
else
head :no_content
end
end
# POST /v1/resources/venues/new
def new
@venue = Venue.new(venue_params)
if @venue.save
render json: @venue, status: :created
else
render json: @venue.errors, status: :unprocessable_entity
end
end
# GET /v1/resources/venues/:name
def show
if @venue
render json: @venue, methods: :image_urls, status: :ok
else
head :no_content
end
end
# PATCH/PUT /v1/resources/venues/:name
def update
if @venue.update(venue_params)
render json: @venue, status: :ok
else
render json: @venue.errors, status: :unprocessable_entity
end
end
# DELETE /v1/resources/venues/:name
def delete
@venue.destroy
head :no_content
end
# POST /v1/resources/venues/:name/images/upload
def upload_images
@venue.images.attach(params[:images])
render json: @venue, methods: :image_urls, status: :ok
end
private
# Use callbacks to share common setup or constraints between actions.
def set_venue
@venue = Venue.find_by(name: params[:name])
end
# Never trust parameters from the scary internet, only allow the white list through.
def venue_params
params.require(:venue).permit(:name, :price, :minimum_bid, :is_published, :currency, :is_expired, :location, :venue_type_id, :user_id, images: [])
end
end
ClassV1::Resources::VenuesController
app/controllers/application\u controller.rb
文件中没有额外的代码
你知道我如何调试这个问题吗?另外,我如何授予未经身份验证的用户访问权限?我希望没有帐户的用户能够浏览场馆。首先,将
加载和授权资源
更改为授权资源
,因为您是手动加载的。在all
操作中手动授权
class V1::Resources::VenuesController < ActionController::API
authorize_resource param_method: :venue_params
skip_authorize_resource only: :all
respond_to :json
before_action :authenticate_user!, except: [:all, :show]
before_action :set_venue, except: [:all, :new]
# GET /v1/resources/venues/all
def all
@venues = Venue.all.where(is_published: true, is_expired: false)
authorize! :read, Venue
if !@venues.empty?
render json: @venues, methods: :image_urls, status: :ok
else
head :no_content
end
end
end
为了让它对未经身份验证的用户起作用,但是
:manage,:all
向未经身份验证的用户打开每个路由。我最后将我的加载和授权行更改为:加载和授权资源参数method::场馆参数,除了:[:all]
,它似乎已经起作用,即使是未经身份验证的用户。@SteveTurczyn你说得对,这是一个例子,更新了answer@DerekC是的,如果您对all
操作不需要任何授权,这是一个不错的选择。我仍然建议您将其更改为simpleauthorize\u resource
以避免向数据库发出额外请求。当我更改为authorize\u resource
时,我仍然在终端中看到相同的数据库查询。