2013-04-08 44 views
6

Tôi đang xây dựng khỏi số a previous discussion I had with Jon Skeet.Tại sao tôi không thể tin tưởng GUID do khách hàng tạo ra? Liệu việc xử lý PK như một tổng hợp của client-GUID và một máy chủ-GUID có giải quyết được gì không?

Các ý chính của kịch bản của tôi là như sau:

  • ứng dụng Client có khả năng tạo ra 'PlaylistItem' đối tượng mới mà cần phải được tiếp tục tồn tại một cơ sở dữ liệu.
  • Trường hợp sử dụng yêu cầu PlaylistItem được tạo theo cách sao cho máy khách không phải chờ phản hồi từ máy chủ trước khi hiển thị PlaylistItem.
  • Khách hàng tạo UUID cho PlaylistItem, hiển thị PlaylistItem trong ứng dụng khách và sau đó phát lệnh lưu vào máy chủ.

Tại thời điểm này, tôi hiểu rằng việc sử dụng UUID được tạo bởi khách hàng là PK của đối tượng trong cơ sở dữ liệu của tôi sẽ là một thực tế không tốt. Lý do cho điều này là một người dùng độc hại có thể sửa đổi UUID được tạo ra và ép buộc các xung đột PK trên DB của tôi.

Để giảm thiểu bất kỳ thiệt hại nào phát sinh từ việc bắt buộc PK trên PlaylistItem, tôi đã chọn xác định PK dưới dạng tổng hợp của hai ID - UUID do khách hàng tạo và GUID do máy chủ tạo. GUID do máy chủ tạo là ID danh sách phát của PlaylistItem.

Bây giờ, tôi đã sử dụng giải pháp này một lúc, nhưng tôi không hiểu tại sao/tin rằng giải pháp của tôi tốt hơn là chỉ tin tưởng vào ID khách hàng. Nếu người dùng có thể ép buộc một đối tác PK với các đối tượng PlaylistItem của người dùng khác thì tôi nghĩ tôi nên cho rằng họ cũng có thể cung cấp PlaylistId của người dùng đó. Họ vẫn có thể ép buộc các đồng đội.

Vì vậy ... vâng. Cách thích hợp để làm điều gì đó như thế này? Cho phép máy khách tạo UUID, máy chủ đưa ra một ngón tay cái lên/xuống khi lưu thành công. Nếu phát hiện thấy va chạm, hãy hoàn nguyên các thay đổi của khách hàng và thông báo cho collison phát hiện?

Trả lời

2

Một giải pháp tốt đẹp sẽ là như sau: Để báo Sam Newman "Building Microservices":

Hệ thống gọi điện thoại sẽ viết BatchRequest, có lẽ đi qua trong một vị trí nơi một tập tin có thể được đặt với tất cả các dữ liệu. Dịch vụ khách hàng sẽ trả lại mã phản hồi HTTP 202, cho biết yêu cầu đã được chấp nhận, nhưng chưa được xử lý. Các gọi hệ thống sau đó có thể thăm dò ý kiến ​​chờ đợi tài nguyên cho đến khi nó lấy một 201 Created chỉ ra rằng yêu cầu đã được hoàn thành

Vì vậy, trong trường hợp của bạn, bạn có thể đăng lên máy chủ nhưng ngay lập tức nhận được một câu trả lời như "Tôi sẽ tiết kiệm PlaylistItem và tôi hứa Id của nó sẽ là cái này ". Sau đó, máy khách (và người dùng) có thể tiếp tục trong khi máy chủ (có thể không phải là API, nhưng một số bộ xử lý nền có thông báo từ API) mất thời gian để xử lý, xác nhận và thực hiện logic khác, có thể nặng cho đến khi nó lưu thực thể. Như đã nêu trước đây, API có thể cung cấp điểm cuối GET cho trạng thái của yêu cầu đó và khách hàng có thể thăm dò ý kiến ​​và hành động tương ứng trong trường hợp có lỗi.

1

Bạn có thể tin tưởng UUID do khách hàng tạo hoặc mã định danh duy nhất toàn cầu tương tự trên máy chủ. Chỉ cần làm điều đó một cách hợp lý.

Hầu hết các bảng/bộ sưu tập của bạn cũng sẽ giữ một userId hoặc có thể tự liên kết với userId thông qua FK.

Nếu bạn đang thực hiện lệnh chèn và người dùng độc hại sử dụng khóa hiện tại thì quá trình chèn sẽ thất bại vì bản ghi/tài liệu đã tồn tại.

Nếu bạn đang thực hiện cập nhật thì bạn nên xác thực rằng người dùng đã đăng nhập sở hữu bản ghi đó hoặc được ủy quyền (ví dụ: người dùng quản trị) để cập nhật. Nếu quyền sở hữu thuần túy đang được thực thi (nghĩa là không có kịch bản người dùng quản trị) thì điều khoản where của bạn trong việc định vị bản ghi/tài liệu sẽ bao gồm cả Id và userId. Bây giờ về mặt kỹ thuật, userId là dư thừa trong mệnh đề where vì Id sẽ tìm duy nhất một bản ghi/tài liệu. Tuy nhiên việc thêm userId đảm bảo rằng bản ghi đó thuộc về người dùng đang thực hiện cập nhật chứ không phải người dùng độc hại.

Tôi giả định rằng có mã thông báo được mã hóa hoặc phiên của một số loại máy chủ đang giải mã để xác định userId và điều này không được máy khách cung cấp nếu không, điều đó rõ ràng là không an toàn.