Gần đây, chúng tôi đã bắt đầu sử dụng Doctrine 2.2 và các phần của Zend Framework 2 trong nỗ lực cải thiện tổ chức, giảm trùng lặp, trong số những thứ khác. Hôm nay, tôi bắt đầu vứt bỏ các ý tưởng để thực hiện một lớp dịch vụ để hoạt động như một trung gian giữa các bộ điều khiển và các thực thể Doctrine.Truy cập dữ liệu và bảo mật trong lớp dịch vụ (Doctrine & ZF)
Hiện tại, phần lớn logic của chúng tôi nằm trong bộ điều khiển. Ngoài ra, chúng tôi sử dụng trình trợ giúp hành động để kiểm tra các quyền nhất định; tuy nhiên, tôi đã đưa ra một cách tiếp cận mới sau khi triển khai Zend \ Di. Tôi bắt đầu tạo các mô hình dịch vụ cụ thể cho thực thể, sử dụng Zend \ Di để tiêm một cá thể EntityManager và các quyền của người dùng hiện tại.
Mã điều khiển như sau:
class Project_DeleteController extends Webjawns_Controller_Action
{
public function init()
{
$this->_initJsonContext();
}
public function indexAction()
{
$response = $this->_getAjaxResponse();
$auditId = (int) $this->_getParam('audit_id');
if (!$auditId) {
throw new DomainException('Audit ID required');
}
/* @var $auditService Service\Audit */
$auditService = $this->getDependencyInjector()->get('Service\Audit');
try {
$auditService->delete($auditId);
$response->setStatusSuccess();
} catch (Webjawns\Exception\SecurityException $e) {
$this->_noAuth();
} catch (Webjawns\Exception\Exception $e) {
$response->setStatusFailure($e->getMessage());
}
$response->sendResponse();
}
}
Và một ví dụ về một trong các lớp dịch vụ của chúng tôi. Hàm khởi tạo nhận hai tham số - một tham số nhận EntityManager và đối tượng Entity \ UserAccess khác - được Zend \ Di tiêm.
namespace Service;
use Webjawns\Service\Doctrine,
Webjawns\Exception;
class Audit extends AbstractService
{
public function delete($auditId)
{
// Only account admins can delete audits
if (\Webjawns_Acl::ROLE_ACCT_ADMIN != $this->getUserAccess()->getAccessRole()) {
throw new Exception\SecurityException('Only account administrators can delete audits');
}
$audit = $this->get($auditId);
if ($audit->getAuditStatus() !== \Entity\Audit::STATUS_IN_PROGRESS) {
throw new Exception\DomainException('Audits cannot be deleted once submitted for review');
}
$em = $this->getEntityManager();
$em->remove($audit);
$em->flush();
}
/**
* @param integer $auditId
* @return \Entity\Audit
*/
public function get($auditId)
{
/* @var $audit \Entity\Audit */
$audit = $this->getEntityManager()->find('Entity\Audit', $auditId);
if (null === $audit) {
throw new Exception\DomainException('Audit not found');
}
if ($audit->getAccount()->getAccountId() != $this->getUserAccess()->getAccount()->getAccountId()) {
throw new Exception\SecurityException('User and audit accounts do not match');
}
return $audit;
}
}
- Đây có phải là một mô hình thích hợp để sử dụng cho những gì chúng tôi đang cố gắng để thực hiện?
- Thực tiễn tốt là có xác thực quyền trong lớp dịch vụ như được đăng?
- Khi tôi hiểu nó, xem logic vẫn nằm trong bộ điều khiển, cho phép mô hình linh hoạt được sử dụng trong các ngữ cảnh khác nhau (JSON, XML, HTML, v.v.). Suy nghĩ?
Tôi hài lòng với cách này hoạt động cho đến nay, nhưng nếu có ai thấy bất kỳ nhược điểm nào về cách chúng tôi đang thực hiện việc này, vui lòng đăng ý kiến của bạn.
Chỉ cần tôi hai xu trên xác thực.Tôi không tin rằng có một cách đúng và một cách sai, tuy nhiên, tôi bắt đầu đưa xác thực của tôi vào lớp dịch vụ, nhưng sau đó chuyển nó vào bộ điều khiển của tôi. Lý do của tôi là lớp dịch vụ là API nội bộ của tôi và tôi nên sử dụng lớp điều khiển của mình để lộ ra thế giới đó, vì vậy nó nên quyết định ai sẽ truy cập vào cái gì. Ngoài ra, nếu tôi muốn xây dựng bất kỳ công cụ/tập lệnh nội bộ nào, tôi không cần phải xây dựng xác thực vào chúng để sử dụng lớp dịch vụ của tôi. –
Cẩn thận không trộn lẫn xác thực và kiểm soát truy cập. Xác thực có thể (nên?) Đi vào mô-đun, trước khi bất kỳ lớp miền được đưa vào hình ảnh. Chỉ khi bạn đã thiết lập danh tính người dùng. Ví dụ: if (! $ AuthService-> hasIdentity()) bên trong mô hình dịch vụ miền của bạn. – dualmon
@JamieSutherland: Tôi không đồng ý. Các dịch vụ xác định logic nghiệp vụ; bộ điều khiển là cầu nối giữa các yêu cầu và logic nghiệp vụ thích hợp. Ví dụ: bạn sẽ chỉ có một dịch vụ duy nhất để đặt hàng một sản phẩm, nhưng bạn có thể có nhiều bộ điều khiển cho các yêu cầu HTTP, yêu cầu API, v.v. Nếu bạn quan tâm đến ACL đang yêu cầu cụ thể (ví dụ, thông qua HTTP, bạn có thể mong đợi một phiên người dùng mà bạn mong đợi một khóa bí mật cho các yêu cầu API), hãy tổng quát việc triển khai ACL của bạn để cho phép điều này. – moteutsch