Triển khai DDD: người dùng và quyền


16

Tôi đang làm việc trên một ứng dụng nhỏ đang cố gắng nắm bắt các nguyên tắc của thiết kế hướng tên miền. Nếu thành công, đây có thể là một thí điểm cho một dự án lớn hơn. Tôi đang cố gắng theo dõi cuốn sách "Thực hiện thiết kế hướng tên miền" (của Vaughn Vernon) và cố gắng thực hiện một diễn đàn thảo luận đơn giản, tương tự. Tôi cũng đã kiểm tra các mẫu IDDD trên github. Tôi có một số khó khăn khi áp dụng Danh tính và Quyền truy cập vào trường hợp của tôi. Hãy để tôi cung cấp một số thông tin cơ bản:

  • Tôi (hy vọng) hiểu lý do đằng sau tách biệt người dùng và logic quyền: đó là một miền hỗ trợ và đó là một bối cảnh bị ràng buộc khác.
  • Trong miền lõi, không có người dùng, chỉ có Tác giả, Người điều hành, v.v. Những thứ này được tạo bằng cách tiếp cận với bối cảnh Nhận dạng và Truy cập bằng cách sử dụng một dịch vụ và sau đó dịch các đối tượng Người dùng đã nhận sang và Người điều hành.
  • Các hoạt động tên miền được gọi với vai trò liên quan là một tham số: vd:

    ModeratePost( ..., moderator);

  • Phương thức của đối tượng miền kiểm tra xem đối tượng Moderator đã cho không phải là null (đối tượng Moderator sẽ là null nếu người dùng được hỏi từ bối cảnh Nhận dạng và Truy cập không có vai trò Moderator).

  • Trong một trường hợp, nó thực hiện kiểm tra bổ sung trước khi thay đổi Bài đăng:

    if (forum.IsModeratedby(moderator))

Câu hỏi của tôi là:

  • Trong trường hợp sau, không phải mối quan tâm bảo mật đã hòa trộn trở lại vào miền lõi? Trước đây các cuốn sách nói "với những người có thể đăng một chủ đề, hoặc trong những điều kiện được phép. Một diễn đàn chỉ cần biết rằng một Tác giả đang làm điều đó ngay bây giờ".

  • Việc triển khai dựa trên vai trò trong cuốn sách khá đơn giản: khi Moderator là miền cốt lõi cố gắng chuyển đổi userId hiện tại thành phiên bản Moderator hoặc thành Tác giả khi cần. Dịch vụ sẽ phản hồi với trường hợp thích hợp hoặc null nếu người dùng không có vai trò bắt buộc. Tuy nhiên, tôi không thể thấy làm thế nào tôi có thể thích ứng điều này với một mô hình bảo mật phức tạp hơn; dự án hiện tại của chúng tôi, tôi đang thử nghiệm có một mô hình khá phức tạp với các nhóm, ACL, v.v.

Ngay cả với các quy tắc không phức tạp lắm, như: "Bài viết chỉ nên được chỉnh sửa bởi Chủ sở hữu hoặc Biên tập viên", cách tiếp cận này dường như bị phá vỡ, hoặc ít nhất là tôi không thấy cách chính xác để thực hiện nó.

Bằng cách hỏi bối cảnh Nhận dạng và Truy cập cho một cá thể Chủ sở hữu, không cảm thấy đúng và tôi sẽ kết thúc với ngày càng nhiều lớp liên quan đến bảo mật trong miền lõi. Ngoài ra, tôi sẽ cần chuyển không chỉ userId, mà cả định danh của tài nguyên được bảo vệ (id của bài đăng, diễn đàn, v.v.) cho bối cảnh bảo mật, có lẽ không nên quan tâm đến những điều này (có đúng không? )

Bằng cách kéo các quyền vào miền lõi và kiểm tra chúng trong các phương thức của các đối tượng miền hoặc trong các dịch vụ, tôi sẽ kết thúc ở ô vuông thứ nhất: trộn các mối quan tâm bảo mật với tên miền.

Tôi đã đọc ở đâu đó (và tôi có xu hướng đồng ý với nó) rằng những thứ liên quan đến quyền này không nên là một phần của miền lõi, trừ khi bảo mật và quyền là chính miền chính. Liệu một quy tắc đơn giản như quy tắc nêu trên có thể biện minh cho việc bảo mật là một phần của miền lõi không?


Có lẽ bạn có thể tìm thấy những gì bạn cần ở đây: stackoverflow.com/a/23485141/329660 Ngoài ra, chỉ vì bối cảnh Kiểm soát truy cập biết về ID tài nguyên không có nghĩa là nó có kiến ​​thức về miền về loại tài nguyên đó là gì hoặc nó là gì làm.
guillaume31

Cảm ơn, tôi đã xem bài đăng đó sớm hơn, vấn đề của tôi chính xác là những gì bản chỉnh sửa nói ở phần cuối: Tôi muốn chuyển quyền kiểm soát truy cập ra khỏi miền chính của mình nhưng tôi cảm thấy mình đã gặp khó khăn khi thực hiện. Tuy nhiên, đề xuất của bạn về ID tài nguyên có ý nghĩa: vì tôi không sử dụng khái niệm Người dùng hoặc Vai trò trong miền lõi nhưng vai trò cụ thể, có thể tôi có thể sử dụng khái niệm Tài nguyên trong bảo mật BC và ánh xạ chúng đến cụ thể liên quan khái niệm miền. Đáng để thử, cảm ơn!
LittlePilgrim

Đừng để các mẫu mã trong liên kết ít nhất trả lời cho "Tôi không thể thấy làm thế nào tôi có thể thích ứng điều này với mô hình bảo mật phức tạp hơn" ?
guillaume31

Vấn đề của tôi không nằm ở việc triển khai mô hình bảo mật, tôi không thể thấy tôi nên ánh xạ các quy tắc phức tạp hơn này vào miền như thế nào. Người dùng -> Ánh xạ tác giả sẽ thay đổi như thế nào nếu đó không phải là mô hình dựa trên vai trò đơn giản về mặt bảo mật? Chuyển ID tài nguyên sang ngữ cảnh khác có thể hoạt động, HasPermissionToEdit(userId, resourceId)nhưng tôi cảm thấy không đúng khi làm nhiễm logic miền với các cuộc gọi này. Có lẽ tôi nên kiểm tra những điều này trong các phương thức dịch vụ ứng dụng, trước khi gọi logic miền?
LittlePilgrim

Tất nhiên nó phải có trong các dịch vụ ứng dụng ... Tôi nghĩ rằng nó rõ ràng từ các phần của mã như UserService @AccessControlList[inf3rno]trong câu trả lời tôi liên kết đến.
guillaume31

Câu trả lời:


6

Đôi khi rất khó để phân biệt giữa các quy tắc kiểm soát truy cập thực và các bất biến miền biên giới trong kiểm soát truy cập.

Đặc biệt, các quy tắc phụ thuộc vào dữ liệu chỉ có sẵn trong quá trình của một phần logic miền cụ thể có thể không dễ dàng rút ra khỏi miền. Thông thường, Kiểm soát truy cập được gọi trước hoặc sau khi thao tác miền được thực hiện nhưng không trong thời gian.

assert (forum.IsModeratedBy(moderator))Ví dụ của Vaughn Vernon có lẽ đã ở ngoài Miền, nhưng không phải lúc nào cũng khả thi.

Tôi sẽ cần chuyển không chỉ userId, mà cả định danh của tài nguyên được bảo vệ (id của bài đăng, diễn đàn, v.v.) vào bối cảnh bảo mật, có lẽ không nên quan tâm đến những điều này (có đúng không?)

Nếu có BC bảo mật và bạn muốn nó xử lý logic đó, thì không cần biết Diễn đàn chi tiết là gì nhưng:

  • Nó chỉ có thể có kiến ​​thức về các khái niệm như "được kiểm duyệt bởi" và cấp hoặc từ chối quyền truy cập tương ứng.
  • Bạn có thể có logic bộ điều hợp đăng ký các sự kiện Tên miền cốt lõi và chuyển chúng sang các cặp giá trị khóa đơn giản (tài nguyên, người dùng được ủy quyền) để Security BC lưu trữ và sử dụng.

Vì cả hai câu trả lời đều hữu ích và ít nhiều đều chỉ về cùng một hướng, tôi đã nâng cao cả hai. Tôi đã chấp nhận điều này, vì @ guillaume31 đã trả lời ít nhiều câu hỏi của tôi về việc triển khai Vernon và tôi sẽ tiếp tục triển khai dựa trên gợi ý của anh ấy về việc sử dụng tài nguyên trong Security BC.
LittlePilgrim

Tôi phải nói rằng tôi nghĩ điều này hoàn toàn trái ngược với câu trả lời của tôi.
Ewan

1
Có thể bây giờ tôi quá bối rối, nhưng cách giải thích của tôi là (cho cả hai câu trả lời): 1. Giữ các vấn đề bảo mật ra khỏi miền và sử dụng BC bảo mật như một dịch vụ 2. Gọi dịch vụ trước khi gọi bất kỳ đối tượng miền nào 3. Dịch vụ sẽ thực hiện ánh xạ từ người dùng / acls đến người điều hành, tác giả, v.v. moderator = securityService.GetModerator(userId, forumId) 4. Logic miền sẽ được triển khai trong các đối tượng này như trong moderator.EditPost () 5. Các phương thức như EditPost sẽ không biết gì về khái niệm bảo mật, sẽ không có kiểm tra bổ sung ở đó
LittlePilgrim

Tôi vẫn đang tự mình tìm kiếm câu trả lời / hướng đi, nhưng tôi thấy rằng bất kỳ logic ủy quyền nào dựa trên trạng thái hiện tại của đối tượng (chẳng hạn như nếu nó hiện được gán cho người điều hành) thực tế là logic kinh doanh thuộc về tên miền của bạn và hơn nữa rằng nếu nó không nằm trong miền của bạn, bạn có nguy cơ kết thúc ở trạng thái không hợp lệ nếu mô hình có thể được cập nhật đồng thời. Chẳng hạn, nếu bạn xác thực quyền sở hữu bằng chính sách và sau đó đi cập nhật đối tượng đó - trong nhiều miền, quyền sở hữu có thể thay đổi và hành động có thể không còn hiệu lực.
Jordan

Trừ khi bạn có bối cảnh hợp tác rất phức tạp, bạn có thể đủ khả năng để thực hiện mô hình đồng thời lạc quan ở đây bằng cách sử dụng phiên bản, nhưng nếu kiểm tra của bạn không được thực hiện trong hoặc ít nhất là đối với một trường hợp tổng hợp cụ thể thì séc của bạn có thể không phù hợp với thực tế trạng thái của đối tượng theo thời gian bạn tiếp tục thay đổi.
Jordan

5

Xác thực và Ủy quyền là một ví dụ tồi cho DDD.

Cả hai điều này đều không phải là một phần của Miền trừ khi công ty của bạn tạo ra các sản phẩm bảo mật.

Yêu cầu doanh nghiệp hoặc tên miền là, hoặc nên là "Tôi yêu cầu xác thực dựa trên vai trò"

Sau đó, bạn kiểm tra vai trò trước khi gọi một chức năng miền.

Trường hợp bạn có các yêu cầu phức tạp như 'Tôi có thể chỉnh sửa các bài đăng của riêng mình nhưng không phải là người khác' đảm bảo rằng tên miền của bạn tách chức năng chỉnh sửa ra EditOwnPost()EditOthersPost()để bạn có một chức năng đơn giản để ánh xạ vai trò

Bạn cũng có thể tách chức năng thành Đối tượng miền, chẳng hạn như Poster.EditPost()Moderator.EditPost()đây là cách tiếp cận OOP hơn, mặc dù lựa chọn của bạn có thể phụ thuộc vào việc phương thức của bạn nằm trong Dịch vụ miền hay Đối tượng miền.

Tuy nhiên, bạn chọn tách mã, ánh xạ vai trò sẽ xảy ra bên ngoài Miền. vì vậy, ví dụ nếu bạn có bộ điều khiển webapi:

PostController : ApiController
{
    [Authorize(Roles = "User")]
    public void EditOwnPost(string postId, string newContent)
    {
        this.postDomainService.EditOwnPost(postId, string newContent);
    }

    [Authorize(Roles = "Moderator")]
    public void EditOtherPost(string postId, string newContent)
    {
        this.postDomainService.EditOtherPost(postId, string newContent);
    }
}

Như bạn có thể thấy mặc dù ánh xạ vai trò được thực hiện trên lớp lưu trữ, logic phức tạp của những gì cấu thành chỉnh sửa bài đăng của riêng bạn hoặc của người khác là một phần của miền.

Tên miền nhận ra sự khác biệt của các hành động, nhưng yêu cầu bảo mật chỉ đơn giản là "chức năng có thể bị giới hạn bởi vai trò" .

Điều này có lẽ rõ ràng hơn với sự phân tách các đối tượng miền, nhưng về cơ bản, bạn đang kiểm tra phương thức xây dựng đối tượng thay vì phương thức gọi phương thức dịch vụ. Yêu cầu của bạn, nếu bạn vẫn muốn nói nó như một phần của miền sẽ trở thành 'chỉ người điều hành mới có thể xây dựng đối tượng người điều hành'


4
Kiểm tra vai trò "tĩnh" là một chút đơn giản. Điều gì xảy ra nếu người điều hành không được phép chỉnh sửa bài đăng của người điều hành khác? Không nên kiểm tra này là một phần của tên miền?
Réda Housni Alaoui

2
@ RédaHousniAlaoui Tôi cũng đang tự hỏi về điều này. Tôi không thể nghĩ ra cách nào để xử lý vấn đề này ngoài việc bao gồm một số đề cập đến Người dùng / Người kiểm duyệt trong miền hoặc thực hiện một số loại logic trong ApiContoder đó để có được vai trò của tác giả bài đăng. Cả hai điều này đều không đúng, và đây là một điều đủ phổ biến trong kinh nghiệm của tôi rằng một số hướng dẫn rõ ràng sẽ cực kỳ hữu ích.
Jimmy

1
@Erwan, trường hợp sử dụng tôi đang nói đến là năng động. Dựa vào câu "Xác thực và ủy quyền là một ví dụ tồi cho DDD" trên các ví dụ về thế giới xin chào là không trung thực. DDD ở đây để tránh sự phức tạp ngẫu nhiên và cho phép quản lý độ phức tạp của miền. Quyền động không phải là một sự phức tạp ngẫu nhiên cũng không phải là điều không xảy ra trong cuộc sống thực.
Réda Housni Alaoui

1
IMHO, vấn đề với giải pháp của bạn là nó không làm hài lòng khách hàng. Khách hàng thường muốn có thể thay đổi các mối quan hệ đó một cách linh hoạt. Hơn nữa, đó cũng là điều xảy ra khi một nhà cung cấp cung cấp cùng một phần mềm doanh nghiệp cho các công ty khác nhau. Nếu phần mềm có khả năng điều chỉnh kém, nhà cung cấp cuối cùng sẽ chết.
Réda Housni Alaoui

1
"Nhưng nó thường được công nhận là" điều xấu ", cài đặt bảo mật của bạn trở nên không thể quản lý được theo thời gian, điều đó có nghĩa là ứng dụng của bạn trở nên không an toàn." Với thiết kế và kiểm tra chính xác, nó hoàn toàn có thể quản lý được. Nhưng, từ XP của tôi, để tạo ra thiết kế chính xác, tên miền phải kiểm tra sự cho phép. Sự thay thế là không tưởng.
Réda Housni Alaoui
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.