स्तरित वास्तुकला में मान्यता और प्राधिकरण


13

मुझे पता है कि आप सोच रहे हैं (या शायद चिल्लाते हुए), "एक और सवाल नहीं पूछ रहा है कि एक स्तरित वास्तुकला में मान्यता कहां है?" खैर, हाँ, लेकिन उम्मीद है कि यह इस विषय पर एक अलग सा होगा।

मैं एक दृढ़ विश्वास है कि मान्यता कई रूप लेती है, संदर्भ-आधारित है और वास्तुकला के प्रत्येक स्तर पर भिन्न होती है। यह पद के लिए आधार है - यह पहचानने में मदद करना कि प्रत्येक परत में किस प्रकार का सत्यापन किया जाना चाहिए। इसके अलावा, एक सवाल जो अक्सर सामने आता है वह यह है कि प्राधिकरण जांच कहां से होती है।

उदाहरण परिदृश्य एक खानपान व्यवसाय के लिए एक आवेदन से आता है। समय-समय पर दिन के दौरान, एक ड्राइवर किसी भी अतिरिक्त नकदी को कार्यालय में बदल सकता है जो ट्रक को साइट से साइट पर ले जाते समय जमा होता है। एप्लिकेशन उपयोगकर्ता को ड्राइवर की आईडी, और राशि एकत्र करके 'कैश ड्रॉप' रिकॉर्ड करने की अनुमति देता है। यहाँ कुछ कंकाल कोड शामिल परतों को चित्रित करने के लिए है:

public class CashDropApi  // This is in the Service Facade Layer
{
    [WebInvoke(Method = "POST")]
    public void AddCashDrop(NewCashDropContract contract)
    {
        // 1
        Service.AddCashDrop(contract.Amount, contract.DriverId);
    }
}

public class CashDropService  // This is the Application Service in the Domain Layer
{
    public void AddCashDrop(Decimal amount, Int32 driverId)
    {
        // 2
        CommandBus.Send(new AddCashDropCommand(amount, driverId));
    }
}

internal class AddCashDropCommand  // This is a command object in Domain Layer
{
    public AddCashDropCommand(Decimal amount, Int32 driverId)
    {
        // 3
        Amount = amount;
        DriverId = driverId;
    }

    public Decimal Amount { get; private set; }
    public Int32 DriverId { get; private set; }
}

internal class AddCashDropCommandHandler : IHandle<AddCashDropCommand>
{
    internal ICashDropFactory Factory { get; set; }       // Set by IoC container
    internal ICashDropRepository CashDrops { get; set; }  // Set by IoC container
    internal IEmployeeRepository Employees { get; set; }  // Set by IoC container

    public void Handle(AddCashDropCommand command)
    {
        // 4
        var driver = Employees.GetById(command.DriverId);
        // 5
        var authorizedBy = CurrentUser as Employee;
        // 6
        var cashDrop = Factory.CreateCashDrop(command.Amount, driver, authorizedBy);
        // 7
        CashDrops.Add(cashDrop);
    }
}

public class CashDropFactory
{
    public CashDrop CreateCashDrop(Decimal amount, Employee driver, Employee authorizedBy)
    {
        // 8
        return new CashDrop(amount, driver, authorizedBy, DateTime.Now);
    }
}

public class CashDrop  // The domain object (entity)
{
    public CashDrop(Decimal amount, Employee driver, Employee authorizedBy, DateTime at)
    {
        // 9
        ...
    }
}

public class CashDropRepository // The implementation is in the Data Access Layer
{
    public void Add(CashDrop item)
    {
        // 10
        ...
    }
}

मैंने 10 स्थानों को इंगित किया है जहाँ मैंने कोड में रखा सत्यापन जाँच देखी है। मेरा प्रश्न यह है कि आप क्या जाँच करेंगे, यदि कोई हो, तो निम्नलिखित व्यवसाय नियमों (प्रत्येक के लिए लंबाई, श्रेणी, प्रारूप, प्रकार, आदि के साथ मानक जाँच के साथ) पर प्रदर्शन कर रहे हैं:

  1. कैश ड्रॉप की मात्रा शून्य से अधिक होनी चाहिए।
  2. कैश ड्रॉप में एक वैध ड्राइवर होना चाहिए।
  3. वर्तमान उपयोगकर्ता को कैश ड्रॉप्स जोड़ने के लिए अधिकृत होना चाहिए (वर्तमान उपयोगकर्ता ड्राइवर नहीं है)।

कृपया अपने विचारों को साझा करें, आपके पास इस परिदृश्य और आपके विकल्पों के कारणों के बारे में कैसे पता चलेगा।


एसई "एक सैद्धांतिक और व्यक्तिपरक चर्चा को बढ़ावा" के लिए बिल्कुल सही मंच नहीं है। मतदान बंद
tdammers

घटिया बयान दिया। मैं वास्तव में सर्वोत्तम प्रथाओं की तलाश कर रहा हूं।
SonOfPirate

2
@tdammers - हाँ यह सही जगह है। कम से कम यह होना चाहता है। एफएक्यू से: 'विशेषण प्रश्नों की अनुमति है।' इसलिए उन्होंने स्टैक ओवरफ्लो की जगह इस साइट को बनाया। क्लोज़ नाज़ी मत बनो। यदि प्रश्न बेकार है, तो यह अस्पष्टता में फीका हो जाएगा।
FastAl

@FastAI: यह इतना 'व्यक्तिपरक' हिस्सा नहीं है, बल्कि 'चर्चा' है जो मुझे परेशान करता है।
tdammers

मुझे लगता है कि आप यहाँ CashDropAmountका उपयोग कर के बजाय एक मूल्य वस्तु होने से मूल्य वस्तुओं का लाभ उठा सकते हैं Decimal। यह जाँचना कि चालक मौजूद है या नहीं, कमांड हैंडलर में किया जाएगा और वही प्राधिकरण नियमों के लिए जाता है। आप कुछ ऐसा करके मुफ्त में प्राधिकरण प्राप्त कर सकते हैं, Approver approver = approverService.findById(employeeId)जहां यह मंजूर नहीं तो कर्मचारी को भूमिका में नहीं। Approverसिर्फ एक मूल्य वस्तु होगी, एक इकाई नहीं। तुम भी अपने कारखाने से छुटकारा पा सकते थे या बजाय एक एआर पर कारखाना विधि का उपयोग कर सकते हैं cashDrop = driver.dropCash(...):।
21

जवाबों:


2

मैं मानता हूं कि आप जो मान्य कर रहे हैं, वह एप्लिकेशन की प्रत्येक परत में भिन्न होगा। मैं आमतौर पर केवल वही मान्य करता हूं जो वर्तमान विधि में कोड को निष्पादित करने के लिए आवश्यक है। मैं अंतर्निहित घटकों को ब्लैक बॉक्स के रूप में मानने की कोशिश करता हूं और उन घटकों को कैसे लागू किया जाता है, इसके आधार पर मान्य नहीं करता।

इसलिए, उदाहरण के रूप में, आपके CashDropApi वर्ग में, मैं केवल यह सत्यापित करूंगा कि 'अनुबंध' शून्य नहीं है। यह NullReferenceException को रोकता है और इस पद्धति को ठीक से निष्पादित करने के लिए आवश्यक सभी है।

मुझे नहीं पता है कि मैं सेवा या कमांड कक्षाओं में कुछ भी मान्य करूंगा और हैंडलर केवल यह सत्यापित करेगा कि कैश कमांड के रूप में 'कमांड' उन्हीं कारणों से शून्य नहीं है। मैंने देखा है (और किया) सत्यापन दोनों तरीकों से कारखाने और इकाई वर्गों के लिए है। एक या दूसरा वह स्थान है जहां आप 'राशि' के मूल्य को मान्य करना चाहते हैं और अन्य पैरामीटर शून्य नहीं हैं (आपके व्यावसायिक नियम)।

रिपॉजिटरी को केवल यह सत्यापित करना चाहिए कि ऑब्जेक्ट में निहित डेटा आपके डेटाबेस में परिभाषित स्कीमा के अनुरूप है और डीएए ऑपरेशन सफल होगा। उदाहरण के लिए, यदि आपके पास एक स्तंभ है जो अशक्त नहीं हो सकता है या उसकी अधिकतम लंबाई हो सकती है, आदि।

जैसा कि सुरक्षा जांच के लिए, मुझे लगता है कि यह वास्तव में इरादे का सवाल है। चूंकि नियम का उद्देश्य अनधिकृत पहुंच को रोकना है, इसलिए मैं इस जांच को जल्द से जल्द करना चाहता हूं, अगर उपयोगकर्ता अधिकृत नहीं है तो मैंने अनावश्यक कदमों की संख्या को कम किया है। मैं शायद इसे CashDropApi में रखूँगा।


1

आपका पहला व्यावसायिक नियम

कैश ड्रॉप की मात्रा शून्य से अधिक होनी चाहिए।

आपकी CashDropइकाई और आपकी AddCashDropCommandकक्षा के एक आक्रमणकारी की तरह दिखता है । ऐसे कुछ तरीके हैं जिनसे मैं एक अपरिवर्तनीय को लागू करता हूं:

  1. अनुबंध मार्ग से डिज़ाइन लें और अपने मामले के आधार पर Preconditions, Postconditions और एक [ContractInvariantMethod] के संयोजन के साथ कोड अनुबंध का उपयोग करें।
  2. कंस्ट्रक्टर / सेटर में स्पष्ट कोड लिखें जो एक ArgumentException को फेंकता है यदि आप 0 से कम राशि में पास करते हैं।

आपका दूसरा नियम प्रकृति में व्यापक है (प्रश्न में विवरण के प्रकाश में): क्या इसका मतलब यह है कि चालक इकाई के पास एक ध्वज है जो दर्शाता है कि वे ड्राइव कर सकते हैं (अर्थात उनका ड्राइविंग लाइसेंस निलंबित नहीं था), क्या इसका मतलब यह है कि चालक था वास्तव में उस दिन काम कर रहा है या इसका मतलब सिर्फ इतना है कि DriverDd, CashDropApi में पारित हो गया, दृढ़ता स्टोर में मान्य है।

इनमें से किसी भी मामले में आपको अपने डोमेन मॉडल को नेविगेट करने और अपने से Driverउदाहरण प्राप्त करने की आवश्यकता होगी IEmployeeRepository, जैसा कि आप location 4अपने कोड उदाहरण में करते हैं। इसलिए, यहां आपको यह सुनिश्चित करने की आवश्यकता है कि रिपॉजिटरी के लिए कॉल शून्य नहीं लौटाती है, इस स्थिति में आपका DriverId मान्य नहीं था और आप किसी भी प्रक्रिया के साथ आगे नहीं बढ़ सकते।

अन्य 2 (मेरे काल्पनिक) चेक के लिए (क्या ड्राइवर के पास वैध ड्राइविंग लाइसेंस है, क्या आज ड्राइवर काम कर रहा था) आप व्यावसायिक नियमों का पालन कर रहे हैं।

मैं यहाँ क्या करने जा रहा हूँ सत्यापनकर्ता वर्गों के एक संग्रह का उपयोग करें जो संस्थाओं पर काम करते हैं (ठीक एरिक इवांस पुस्तक - डोमेन ड्रिवेन डिज़ाइन से विनिर्देशन पैटर्न की तरह )। मैंने इन नियमों और सत्यापनकर्ताओं के निर्माण के लिए FluentValidation का उपयोग किया है । फिर मैं सरल नियमों से अधिक जटिल / अधिक पूर्ण नियमों की रचना (और इसलिए पुन: उपयोग) कर सकता हूं। और मैं तय कर सकता हूं कि उन्हें चलाने के लिए मेरी वास्तुकला में कौन सी परतें हैं। लेकिन मैंने उन सभी को एक जगह पर इनकोड किया है, पूरे सिस्टम में नहीं।

आपका तीसरा नियम एक क्रॉस-कटिंग चिंता से संबंधित है: प्राधिकरण। चूंकि आप पहले से ही एक IoC कंटेनर का उपयोग कर रहे हैं (यह मानते हुए कि आपका IoC कंटेनर विधि अवरोधन का समर्थन करता है) तो आप कुछ AOP कर सकते हैं । एक अप्सरा लिखें जो प्राधिकरण करता है और आप अपने IoC कंटेनर का उपयोग इस प्राधिकरण व्यवहार को इंजेक्ट करने के लिए कर सकते हैं जहाँ इसकी आवश्यकता है। यहां बड़ी जीत यह है कि आपने तर्क को एक बार लिखा है, लेकिन आप इसे अपने सिस्टम में पुन: उपयोग कर सकते हैं।

डायनेमिक प्रॉक्सी (कैसल विंडसर, स्प्रिंग.नेट, निनजेक्ट 3.0, आदि) के माध्यम से अवरोधन का उपयोग करने के लिए आपके लक्ष्य वर्ग को एक आधार वर्ग से एक इंटरफ़ेस या विरासत को लागू करने की आवश्यकता होती है। आप कॉल करने से पहले लक्ष्य विधि को रोकेंगे, उपयोगकर्ता के प्राधिकरण की जांच करेंगे और कॉल को वास्तविक विधि से आगे बढ़ने से रोकेंगे (उपयोगकर्ता को फेंकें, लॉग करें, विफलता का संकेत देने वाला मान लौटाएं, या कुछ और) यदि उपयोगकर्ता के पास नहीं है ऑपरेशन करने के लिए सही भूमिकाएँ।

आपके मामले में आप कॉल को इंटरसेप्ट कर सकते हैं

CashDropService.AddCashDrop(...) 

AddCashDropCommandHandler.Handle(...)

यहाँ समस्याएँ हो CashDropServiceसकती हैं, जिन्हें इंटरसेप्ट नहीं किया जा सकता क्योंकि कोई इंटरफ़ेस / बेस क्लास नहीं है। या AddCashDropCommandHandlerआपके IoC द्वारा नहीं बनाया जा रहा है, इसलिए आपका IoC कॉल को इंटरसेप्ट करने के लिए डायनेमिक प्रॉक्सी नहीं बना सकता है। स्प्रिंगनेट की एक उपयोगी विशेषता है जहां आप असेंबली में एक वर्ग पर रेगेक्स के माध्यम से एक विधि को लक्षित कर सकते हैं, इसलिए यह काम कर सकता है।

उम्मीद है इससे आपको कुछ विचार मिलेंगे।


क्या आप बता सकते हैं कि मैं इस प्राधिकरण व्यवहार को इंजेक्ट करने के लिए आपके IoC कंटेनर का उपयोग कैसे करूंगा? यह अच्छा लग रहा है लेकिन AOP और IoC को एक साथ काम करना मुझे अब तक बचता है।
SonOfPirate

बाकी के रूप में, मैं कंस्ट्रक्टर में सत्यापन रखने और / या बसने के लिए सहमत हूं ताकि ऑब्जेक्ट को अमान्य स्थिति में प्रवेश करने से रोका जा सके (हमलावरों को संभालना)। लेकिन इससे परे और ड्राइवर का पता लगाने के लिए IEmployeeRepository पर जाने के बाद अशक्त चेक का संदर्भ, आप कोई भी विवरण प्रदान नहीं करते हैं जहां आप बाकी सत्यापन करेंगे। FluentValidation के उपयोग और पुन: उपयोग आदि को देखते हुए, यह दिए गए मॉडल में नियमों को कहां लागू करेगा?
SonOfPirate

मैंने अपना उत्तर संपादित कर दिया है - देखें कि क्या यह मदद करता है। जैसा कि "आप दिए गए मॉडल में नियम कहां लागू करेंगे?" शायद आपके कमांड हैंडलर में लगभग ४, ५, ६,,। आपके पास रिपॉजिटरी तक पहुंच है जो आपको व्यावसायिक स्तर पर सत्यापन करने के लिए आवश्यक जानकारी दे सकती है। लेकिन मुझे लगता है कि अन्य लोग भी हैं जो मुझसे यहाँ असहमत होंगे।
राबर्ट्स

स्पष्ट करने के लिए, सभी निर्भरताएं इंजेक्ट की जा रही हैं। संदर्भ कोड को संक्षिप्त रखने के लिए मैंने उसे छोड़ दिया। मेरी जांच में पहलू के भीतर निर्भरता होने के साथ अधिक है क्योंकि पहलुओं को कंटेनर के माध्यम से इंजेक्ट नहीं किया जाता है। उदाहरण के लिए, प्राधिकरण प्राधिकरण को संदर्भ प्राधिकरण सेवा का संदर्भ कैसे मिलता है?
SonOfPirate

1

नियमों के लिए:

1- कैश ड्रॉप की मात्रा शून्य से अधिक होनी चाहिए।

2- कैश ड्रॉप में एक वैध ड्राइवर होना चाहिए।

3- वर्तमान उपयोगकर्ता को कैश ड्रॉप्स जोड़ने के लिए अधिकृत होना चाहिए (वर्तमान उपयोगकर्ता ड्राइवर नहीं है)।

मैं व्यापार नियम (1) के लिए स्थान (1) में सत्यापन करूंगा और यह सुनिश्चित करूंगा कि नियम (2) के लिए पूर्व जांच के रूप में आईडी शून्य या नकारात्मक नहीं है (शून्य मान्य है)। कारण यह है कि "गलत डेटा के साथ एक परत सीमा पार न करें जो आप उपलब्ध जानकारी से जांच सकते हैं" का मेरा नियम है। इसका अपवाद यह होगा कि यदि सेवा अन्य कॉलर्स के लिए अपने कर्तव्य के हिस्से के रूप में सत्यापन करती है। जिस स्थिति में, यह केवल वहाँ सत्यापन के लिए पर्याप्त होगा।

नियमों (2) और (3) के लिए, इसे डेटाबेस एक्सेस लेयर (या db लेयर) पर ही किया जाना चाहिए क्योंकि इसमें DB एक्सेस शामिल है। जानबूझकर परतों के बीच यात्रा करने की आवश्यकता नहीं है।

विशेष रूप से नियम (3) से बचा जा सकता है यदि हम जीयूआई को अनधिकृत उपयोगकर्ताओं को इस परिदृश्य को सक्षम करने वाले बटन को धक्का देने से रोकते हैं। जबकि यह कोड के लिए कठिन है, यह बेहतर है।

अच्छा प्रश्न!


+1 प्राधिकरण के लिए - इसे UI में डालना एक विकल्प है जिसका मैंने अपने उत्तर में उल्लेख नहीं किया है।
रॉबर्ट्स

यूआई में प्राधिकरण चेक होने के दौरान उपयोगकर्ता के लिए एक अधिक इंटरैक्टिव अनुभव प्रदान करता है, मैं एक सेवा-आधारित एपीआई विकसित कर रहा हूं और कॉल करने वाले ने क्या नियम लागू किए हैं या नहीं इस बारे में कोई धारणा नहीं बना सकता है। ऐसा इसलिए है क्योंकि इनमें से कई चेक यूआई को आसानी से सौंपे जा सकते हैं जिन्हें मैंने पोस्ट के लिए आधार के रूप में एपीआई परियोजना का उपयोग करने के लिए चुना था। मैं पाठ्यपुस्तक के बजाय जल्दी और आसानी से सर्वोत्तम प्रथाओं की तलाश कर रहा हूं।
SonOfPirate

@SonOfPirate, INMO, UI को सत्यापन करने की आवश्यकता है क्योंकि यह तेज़ है और इसमें सेवा (कुछ मामलों में) की तुलना में अधिक डेटा है। अब सेवा को अपनी वैधता किए बिना अपनी सीमा के बाहर डेटा नहीं भेजना चाहिए क्योंकि यह तब तक अपनी जिम्मेदारियों का हिस्सा है जब तक आप चाहते हैं कि सेवा ग्राहक पर भरोसा न करे। तदनुसार, मेरा सुझाव है कि आगे की प्रक्रिया के लिए डेटाबेस को डेटा भेजने से पहले सेवा में (फिर से) गैर-डीबी चेक किए जाएं।
NoChance
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.