Kiểm tra quyền người dùng nên diễn ra ở đâu và MVC và bởi ai?


26

Kiểm tra sự cho phép của người dùng nên diễn ra trong mô hình hoặc bộ điều khiển? Và ai nên xử lý các kiểm tra quyền, đối tượng Người dùng hoặc một số trình trợ giúp Người dùng Quản lý?

Nó nên xảy ra ở đâu?

Kiểm tra trong Bộ điều khiển:

class MyController {
  void performSomeAction() {
    if (user.hasRightPermissions()) {
      model.someAction();
    }
  }
  ...

Việc kiểm tra trong Bộ điều khiển giúp thực hiện các Mô hình hành động đơn giản, vì vậy chúng tôi có thể giữ tất cả logic cho Bộ điều khiển.

Kiểm tra trong Mô hình:

class MyModel {
  void someAction() {
    if (user.hasRightPermissions()) {
      ...
    }
  }
  ...

Bằng cách đặt các kiểm tra vào Mô hình, chúng tôi sẽ làm phức tạp Mô hình, nhưng cũng đảm bảo rằng chúng tôi không vô tình cho phép người dùng làm những việc mà họ không cần phải có trong Bộ điều khiển.

Và bởi ai?

Khi chúng tôi đã giải quyết tại chỗ, ai nên kiểm tra? Người dùng?

Class User {
  bool hasPermissions(int permissionMask) {
    ...
  }
  ...

Nhưng đó không thực sự là trách nhiệm của người dùng để biết những gì anh ta hoặc cô ta có thể giải quyết, vì vậy có lẽ một số lớp người trợ giúp?

Class UserManagement {
  bool hasPermissions(User user, int permissionMask) {
    ...
  }
  ...

Tôi biết rằng thông thường chỉ hỏi một câu hỏi trong một câu hỏi, nhưng tôi nghĩ những câu hỏi này có thể được trả lời độc đáo cùng nhau.

Câu trả lời:


20

Như thường lệ, "nó phụ thuộc"

  • kiểm tra sự cho phép sẽ có chức năng làm việc bất cứ nơi nào nó thuận tiện để đặt chúng,
  • nhưng nếu bạn đang hỏi một câu hỏi kỹ thuật thì câu trả lời có thể là 'đặt các kiểm tra vào đối tượng sở hữu dữ liệu cần thiết để thực hiện kiểm tra' (có thể là bộ điều khiển).
  • nhưng nếu bạn đang hỏi một câu hỏi triết học, tôi đề nghị một câu trả lời thay thế: không cho người dùng thấy những hành động mà họ không được phép thực hiện .

Vì vậy, trong trường hợp sau, bạn có thể có kiểm tra quyền trong bộ điều khiển được triển khai như một thuộc tính boolean và liên kết thuộc tính đó với thuộc tính Hiển thị của nút hoặc bảng trong giao diện người dùng điều khiển hành động

với tư cách là người dùng, thật khó chịu khi thấy các nút cho các hành động mà tôi không thể thực hiện; cảm giác như mình bị bỏ rơi khỏi cuộc vui;)


Ứng dụng của chúng tôi thực hiện kịch bản thứ ba với ngoại lệ là chúng tôi không ẩn các điều khiển, chúng tôi vô hiệu hóa chúng. Thật không may, tất cả đều được thực hiện trong mã Winforms phía sau, vì vậy nó không thực sự liên quan đến câu hỏi OP.
Dave Nay

11
"Thật bực bội khi thấy các nút cho các hành động mà tôi không thể thực hiện" -> Cố gắng nâng cao bài đăng của chính bạn :)
Rowan Freeman

5
Không đủ để chỉ ẩn các nút cho các hành động mà người dùng không thể thực hiện, máy chủ phải kiểm tra mọi yêu cầu cho phép. Mục đạn thứ ba không phải là "câu trả lời thay thế", đây là việc cần làm ngoài việc kiểm tra quyền truy cập phía máy chủ.
Flimm

@Flimm đồng ý, nếu các yêu cầu được xử lý bởi một máy chủ; câu hỏi cụ thể là về lớp Người điều khiển
Steven A. Lowe

7

Bảo mật là một mối quan tâm xuyên suốt, do đó cần phải được thực hiện trong nhiều lớp. Dưới đây là một ví dụ cho MVC nhưng khái niệm này áp dụng cho các kiến ​​trúc và / hoặc các mẫu khác, bạn chỉ cần xác định các điểm thực thi.

Nó nên xảy ra ở đâu?

Chế độ xem có thể chứa các thành phần UI (widget, nút, menu, v.v.) cần được hiển thị hoặc không cho một số người dùng, dựa trên quyền của họ. Đây có thể là trách nhiệm của công cụ xem , vì bạn không muốn mọi chế độ xem tự xử lý việc này. Tùy thuộc vào loại yếu tố bạn ủy quyền cho bạn, hãy chuyển trách nhiệm này sang nơi khác. Ví dụ, nghĩ về một menu trong đó một số mặt hàng phải được hiển thị và một số không. Các mục có thể được triển khai dưới dạng danh sách ở đâu đó và lọc danh sách đó dựa trên quyền sau đó chuyển tiếp nó đến dạng xem.

Bộ điều khiển phản hồi các yêu cầu, vì vậy nếu người dùng không có quyền thực thi một hành động thì nên kiểm tra trước khi hành động được gọi, chuyển trách nhiệm cho người gọi hành động thay vì giữ nó trong bộ điều khiển. Điều này có lợi thế là giữ cho bộ điều khiển của bạn sạch sẽ và nếu có gì đó thay đổi trong các quyền bạn không phải chọn lọc qua bộ điều khiển của mình để áp dụng những thay đổi đó.

Tài nguyên được hiển thị dựa trên quyền. Điều này thường được thực hiện ở cấp cơ sở dữ liệu , vì bạn không muốn lấy mọi thứ từ cơ sở dữ liệu và sau đó áp dụng quyền.

Như bạn có thể thấy, tùy thuộc vào những gì bạn muốn ủy quyền, có những nơi khác nhau nên thực hiện việc này. Mục tiêu là càng không phô trương càng tốt, để khi chính sách bảo mật của bạn thay đổi, bạn có thể dễ dàng áp dụng nó, tốt nhất là không thay đổi mã ứng dụng của bạn. Điều này có thể không hợp lệ đối với các ứng dụng nhỏ, trong đó bộ quyền là khá nhỏ và không thay đổi thường xuyên. Trong các ứng dụng doanh nghiệp, câu chuyện hoàn toàn khác.

Ai nên làm điều đó?

Rõ ràng không phải là người mẫu. Mỗi lớp nên có một điểm thực thi xử lý ủy quyền. Văn bản in nghiêng ở trên nêu bật điểm thực thi có thể cho mỗi cấp.

Hãy xem XACML . Bạn không cần phải thực hiện nó như vậy, nhưng nó sẽ cung cấp cho bạn một số hướng mà bạn có thể làm theo.


Đây là câu trả lời tốt nhất. Vì một số lý do, người đứng đầu và những người khác giải quyết sự khác biệt giữa bộ điều khiển và chế độ xem, hoặc chế độ xem và mô hình, đó không phải là điều OP đang yêu cầu. Cảm ơn!
redFur

1

Tôi sử dụng chương trình sau đây. Điều đáng nói là hầu hết các kiểm tra quyền của người dùng có thể được chia thành hai trường hợp chung:

  • người dùng truy cập vào hành động của bộ điều khiển dựa trên vai trò người dùng mà không kiểm tra hành động tham số được gọi với,
  • người dùng truy cập vào mô hình dựa trên bất kỳ logic hoặc mối quan hệ nào giữa người dùng cụ thể và mô hình cụ thể.

Truy cập vào hành động của bộ điều khiển mà không kiểm tra các thuộc tính thường được thực hiện trong các khung MVC. Điều này hoàn toàn đơn giản: bạn xác định quy tắc, người dùng của bạn có vai trò. Bạn chỉ cần kiểm tra xem người dùng có quyền hành động tra cứu vai trò của nó trong các quy tắc hay không.

Người dùng nên truy cập vào mô hình cụ thể trong mô hình. (Diễn viên là lớp người dùng cơ sở. Giả sử đó có thể là khách hàng, người bán hoặc khách.)

interface ICheckAccess
{
    public function checkAccess(Actor $actor, $role);
}

class SomeModel implements ICheckAccess
{
    public function checkAccess(Actor $actor, $role)
    {
        // Your permissions logic can be as sophisticated as you want.
    }
}

Đặt logic đó trong mô hình mang lại một số lợi nhuận. Phương thức kiểm tra truy cập có thể được kế thừa, bạn không cần tạo thêm bất kỳ lớp nào, bạn có thể sử dụng các lợi thế OOP chung.

Tiếp theo, để đơn giản hóa việc kiểm tra truy cập, chúng tôi đưa ra một số giả định gần như luôn được triển khai vì đơn giản và phong cách tốt:

  • bộ điều khiển thường liên quan đến một số lớp mô hình;
  • các hành động được kiểm tra để truy cập lấy id mô hình duy nhất làm tham số;
  • tham số này luôn có thể được truy cập thống nhất từ ​​phương thức của lớp trình điều khiển cơ sở;
  • hành động được đặt trong bộ điều khiển tương ứng với mô hình mà hành động id thực hiện.

Với các giả định này, các hành động sử dụng id mô hình có thể được liên kết với thể hiện mô hình cụ thể. Trên thực tế, hầu hết các hành động có thể dễ dàng được chuyển đổi và di chuyển để phù hợp với các giả định đã nêu ở trên.

Sau đó, một số lớp trình điều khiển trừu tượng cơ sở nên được định nghĩa và kế thừa.

abstract class ModelController
{
    // Retrieve model from database using id from action parameter.
    public abstract function loadModel($id);

    // Returns rules for user role to pass to SomeModel::checkAccess()
    // Something like array('view' => 'viewer', 'delete' => 'owner', 'update' => 'owner')
    public abstract function modelRules();

    public abstract fucntion getIdParameter();

    public function filterModelAccess()
    {
        $id = $this->getIdParameter();
        if(!$this->checkModelAccess($id))
            throw new HttpException(403);
    }

    public function checkModelAccess($id)
    {
        $model = $this->loadModel($id);
        $actor = My::app()->getActor();
        $rules = $this->modelRules();
        $role = $rules[My::app()->getActionName()];
        return $model->chechAccess($actor, $role);
    }
}

Bạn có thể gọi phương thức someControll :: checkModelAccess ($ id) khi bạn xây dựng các menu của mình và quyết định có hiển thị một số liên kết hay không.


Tôi xin lỗi vì PHP.
George Sovetov

1

Trong cả Model View

Trong Chế độ xem - vì Giao diện người dùng không hiển thị các thành phần UI bị hạn chế cho người dùng hiện tại

(như, giả sử, nút "Xóa" phải được hiển thị cho những người có quyền thích hợp)

Trong Mô hình - vì ứng dụng của bạn có thể có một số loại API, phải không? API cũng phải kiểm tra quyền và có thể sử dụng lại Mô hình.

(như, giả sử, bạn có nút "Xóa" trong giao diện người dùng phương thức API "http: / server / API / DeleteEntry / 123" cùng một lúc


Tại sao bạn chọn mô hình trên bộ điều khiển?
Flimm

không chắc chắn tại sao xem, mô hình và không trong bộ điều khiển, nơi hầu hết thời gian được thực hiện.
VP.

@VP bộ điều khiển không có khả năng hiển thị / ẩn các thành phần UI (ngoài việc chuyển một bool-var TO THE VIEW)
jitbit

Tôi không biết, mọi nơi thường được thực hiện trong lớp điều khiển, đó là lý do tại sao tôi tò mò.
VP.

0

MVC là một mẫu trình bày. Vì quan điểm và bộ điều khiển như vậy chỉ nên có trách nhiệm liên quan đến việc trình bày. Một số quyền áp dụng cho bản trình bày, như chế độ chuyên gia, tính năng UI thử nghiệm hoặc các thiết kế khác nhau. Những người có thể được xử lý bởi bộ điều khiển MVC.

Nhiều loại quyền khác có liên quan trên một số lớp của ứng dụng. Ví dụ: nếu bạn muốn có người dùng chỉ có thể xem dữ liệu và không thay đổi mọi thứ:

  • lớp trình bày phải ẩn các tính năng chỉnh sửa
  • Nếu một tính năng chỉnh sửa được gọi bằng mọi cách thì điều này có thể / nên được phát hiện (bởi các phần cụ thể của ứng dụng trong lớp nghiệp vụ, không phải phần cụ thể miền của nó - TrainEditor, không phải Train) và có thể gây ra ngoại lệ
  • Lớp truy cập dữ liệu cũng có thể kiểm tra ghi, nhưng đối với các loại quyền phức tạp hơn nhanh chóng đòi hỏi quá nhiều kiến ​​thức về lớp doanh nghiệp là một ý tưởng tốt.

Có một số trùng lặp trong phương pháp này. Nhưng vì bản trình bày thường không ổn định, người ta có thể tạo ra một trường hợp tốt để kiểm tra quyền trong phần thường ổn định hơn của ứng dụng, ngay cả khi điều đó có nghĩa là một số kiểm tra dự phòng trong trường hợp lớp trình bày hoạt động như dự định.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.