2015-06-15 15 views
18

Tôi có tuyến đường RESTful điển hình cho một người sử dụng:Thực hành tốt nhất định tuyến RESTful khi tham chiếu current_user từ tuyến đường?

/user/:id 
/user/:id/edit 
/user/:id/newsfeed 

Tuy nhiên con đường /user/:id/edit chỉ có thể được truy cập khi id bằng id của CURRENT_USER. Vì tôi chỉ muốn current_user có quyền truy cập để chỉnh sửa hồ sơ của nó. Tôi không muốn người dùng khác có thể chỉnh sửa tiểu sử không thuộc về họ.

Phương pháp hay nhất để xử lý tình huống này là gì?

Tôi có nên thoát khỏi tuyến đường và thông qua lỗi nếu current_user.id != param[:id], buộc ứng dụng khách kết thúc cuộc gọi gọi api để theo dõi id của người dùng đã đăng nhập không?

Tôi có nên thực hiện tuyến đường đặc biệt /user/self/edit và trong bộ điều khiển để kiểm tra xem param[:id] == 'self'?

+1

Các đường ray tiêu chuẩn cách sẽ được kiểm tra id đối với người dùng hiện tại trong before_filter/before_action hoặc làm anwer được chấp nhận và tải tài nguyên dựa trên current_user – engineerDave

Trả lời

11

Tôi đã thêm các tuyến đường đặc biệt cho hành động hồ sơ người dùng hiện tại, trong trường hợp này bạn không phải kiểm tra bất kỳ điều gì. Chỉ cần tải và hiển thị dữ liệu của người dùng hiện tại. Ví dụ:

/my-profile/edit 
/my-profile/newsfeed 

Nó không phải là RESTful nhưng bạn không phải đặt thêm kiểm tra để giữ mã của bạn sạch sẽ.

Nếu bạn vẫn phải có (hoặc muốn có) một tuyến đường RESTful nghiêm ngặt thì tôi sẽ sử dụng before_filter và kiểm tra xem id = current_user.id. Nếu không thì trả lại 401 hoặc 403.

+0

Vâng, bạn có thể xem xét '/ profile' là tài nguyên và tôi thậm chí sẽ đổi tên url thứ hai thành'/newsfeed' , là nguồn cấp tin tức của người dùng hiện tại. – nathanvda

-1

Bạn nên sử dụng tuyến đường này:

PUT /user/me 

Lưu ý rằng không có nhu cầu "chỉnh sửa": bạn nên sử dụng phương pháp PUT để thay thế.

Ngoài ra, bạn nên xác định rõ ràng tuyến đường tôi đã viết ở trên, thay vì kiểm tra xem id == 'self'.

5

Tôi chỉ muốn current_user có quyền truy cập để chỉnh sửa tiểu sử của nó. Tôi không muốn người dùng khác có thể chỉnh sửa tiểu sử không thuộc về số họ.

gì tôi đề nghị là sử dụng một số đá quý uỷ quyền như pundit

Mẫu mã:

class UserPolicy 
    attr_reader :current_user, :model 

    def initialize(current_user, model) 
    @current_user = current_user 
    @user = model 
    end 

    def edit? 
    @current_user == @user 
    end 
end 

Ngoài ra với một viên ngọc xác thực như Devise, chỉ có current_user (người dùng đã đăng nhập) chỉ có thể ccess và chỉnh sửa hồ sơ của họ

0

Bạn nên giữ url như vậy. Xác thực và ủy quyền là những mối quan tâm riêng biệt. 'current_user' đề cập đến người dùng được xác thực để truy cập apis. Id trong url xác định tài nguyên mà 'current_user' đang hoạt động, do đó, anh ta có quyền truy cập vào tài nguyên đó hay không là mối quan tâm của ủy quyền. Vì vậy, bạn nên thêm current_user.id != param[:id] (như bạn đã đề cập) trong quyền api của bạn và ném 403 mã trạng thái để phản hồi.

2

Tôi sẽ nói rằng bạn đang làm đúng, chỉ cần giữ lộ trình hiện tại của bạn như hiện tại. Và những gì bạn nên làm là thêm một hạn chế trong bộ điều khiển của bạn để thay thế. Tôi cho rằng bạn đang sử dụng Rails và làm việc trên users_controller.

class UsersController < ApplicationController::Base 
    def edit 
    if current_user.id == params[:id] 
     # do your work 
    else 
     render :404 
    end 
    end 
end 

Hoặc bạn có thể dọn dẹp điều khiển của bạn bằng cách di chuyển hạn chế vào một callback thay vì:

class UsersController < ApplicationController::Base 
    before_filter :restrict_user, only: [:edit] 

    def edit 
    # do your work 
    end 

    private 
    def restrict_user 
    render :404 unless current_user.id == params[:id] 
    end 
end 
2

Bạn có thể thêm gem "cancancan" và sau khi khởi tạo ....

class Ability 
     include CanCan::Ability 

     def initialize(user) 

      can :update, User do |user| 
       user.id == params[:id] 
      end 
     end 
    end 

Sau đó, thêm số này authorize! :edit, @user vào hành động cập nhật của bạn

2

Bạn là g oing cần thêm mã ủy quyền trong tất cả các phương thức user_controller như một chú thích khác được đề xuất. Thông thường những gì tôi làm trong các ứng dụng mà người dùng chỉ phải chỉnh sửa tiểu sử của riêng mình, tôi thêm tuyến đường/hồ sơ để người dùng chỉnh sửa tiểu sử của riêng họ và sau đó trên các tuyến chính/người dùng /: id/* tôi thêm logic để ngăn không người dùng -admin truy cập vào các tuyến đường đó.

2

Người dùng có thể xem tiểu sử của mình /users/1 hoặc chỉnh sửa tiểu sử của mình /users/1/edit. Từ góc độ người dùng, các URL này hoàn toàn ổn.

Không có liên kết nào có thể dẫn người dùng chỉnh sửa người dùng khác. Bạn đang cố gắng đề cập đến tình huống khác nhau: khi người nào đó cố gắng tạo thủ công URL và có quyền truy cập vào một tài khoản khác. Tôi sẽ không gọi họ là tin tặc, nhưng về mặt kỹ thuật họ là - những người dùng đang cố gắng khai thác trang web của bạn để vượt qua các hạn chế.

Bạn không phải lo lắng về tính năng "tin tặc" tiện lợi. Tôi luôn sử dụng current_user trong hành động edit để không ai có thể chỉnh sửa tiểu sử sai bất kể hồ sơ của anh ấy là gì.

def edit 
    @user = current_user 
end 

Ngoài ra, tôi cần đề cập rằng bạn cũng nên thực hiện hành động update. Với edit bạn chỉ có thể nhận dữ liệu (và có lẽ chỉ có dữ liệu mở công khai rộng, trừ khi bạn đặt thông tin thanh toán hoặc mật khẩu thuần văn bản bên trong mẫu edit). Nhưng với update, bạn thực sự có thể thay đổi dữ liệu, điều này có thể phá hoại nhiều hơn.

1

Vì bạn chỉ quan tâm để cung cấp thiết bị đầu cuối RESTful chỉ cho người sử dụng hiện chứng thực, trong đó có sẵn trong bộ điều khiển của bạn như current_user, tôi nói rằng bạn không cần tham số id nhận dạng. Tôi đề nghị sử dụng các tuyến đường sau:

GET /user => users#show 
PUT/PATCH /user => users#update 
GET /user/edit => users#edit 
2

Bởi vì có vẻ như rằng chỉ có tài nguyên sử dụng có sẵn nên là người dùng xác thực, tôi nghĩ rằng cách tốt nhất để giải quyết này là

GET /user 
PUT /user 
GET /user/newsfeed 

Nếu bạn muốn mở rộng việc sử dụng api trong tương lai để một người dùng có thể có quyền truy cập vào các tài nguyên người dùng khác, hơn là bạn cần một giải pháp bao gồm các id người dùng. Ở đây nó có ý nghĩa để giới thiệu các tuyến đường cho "tự", quá. Nhưng sau đó bạn cũng phải thực hiện kiểm tra truy cập ở phía máy chủ.

GET /user/id/:id 
PUT /user/id/:id 
GET /user/id/:id/newsfeed 

GET /user/self 
PUT /user/self 
GET /user/self/newsfeed 

Nhưng tôi nghĩ rằng bạn nên giữ nó càng đơn giản càng tốt

Đối với điều tra thêm tôi sẽ đề xuất các cuốn sách như http://apigee.com/about/resources/ebooks/web-api-design đó đưa ra một giới thiệu tốt vào thiết kế API

Các vấn đề liên quan