किसी समस्या को हल करने के कई तरीके हैं, और सॉफ्टवेयर सिस्टम में भूमिकाओं और उपयोगकर्ता की स्थिति को प्रशासित करने के मामले में ऐसा ही है। इस लेख में आपको उस विचार का सरल विकास और साथ ही कुछ उपयोगी टिप्स और कोड नमूने मिलेंगे।
मूल विचार
अधिकांश प्रणालियों में, आमतौर पर भूमिकाओं . की आवश्यकता होती है और उपयोगकर्ता स्थितियां ।
भूमिकाएँ अधिकारों . से संबंधित हैं जो उपयोगकर्ता सफलतापूर्वक लॉग इन करने के बाद सिस्टम का उपयोग करते समय करते हैं। भूमिकाओं के उदाहरण "कॉल सेंटर कर्मचारी", "कॉल सेंटर मैनेजर", "बैक ऑफिस कर्मचारी", "बैक ऑफिस मैनेजर" या "मैनेजर" हैं। आम तौर पर इसका मतलब है कि उपयोगकर्ता के पास कुछ कार्यक्षमता तक पहुंच होगी यदि उसके पास उपयुक्त भूमिका है। यह मान लेना बुद्धिमानी है कि एक उपयोगकर्ता की एक ही समय में कई भूमिकाएँ हो सकती हैं।
क़ानून बहुत सख्त हैं और वे निर्धारित करते हैं कि उपयोगकर्ता के पास सिस्टम में लॉग इन करने का अधिकार है या नहीं। एक उपयोगकर्ता की केवल एक स्थिति हो सकती है एक ही समय पर। स्थितियों के उदाहरण होंगे:"काम कर रहे", "छुट्टी पर", "बीमार छुट्टी पर", "अनुबंध समाप्त"।
जब हम किसी उपयोगकर्ता की स्थिति बदलते हैं तब भी हम उस उपयोगकर्ता से संबंधित सभी भूमिकाओं को अपरिवर्तित रख सकते हैं। यह बहुत मददगार है क्योंकि ज्यादातर समय हम केवल उपयोगकर्ता की स्थिति को बदलना चाहते हैं। यदि कॉल सेंटर कर्मचारी के रूप में काम करने वाला कोई उपयोगकर्ता छुट्टी पर जाता है, तो हम उसकी स्थिति को "छुट्टी पर" में बदल सकते हैं और उसके वापस आने पर उसे "काम कर रहे" स्थिति में वापस कर सकते हैं।
लॉगिन के दौरान परीक्षण भूमिकाएं और स्थितियां हमें यह तय करने में सक्षम बनाती हैं कि क्या होगा। उदाहरण के लिए, हो सकता है कि उपयोगकर्ता नाम और पासवर्ड सही होने पर भी हम लॉगिन को मना करना चाहते हों। हम ऐसा कर सकते हैं यदि वर्तमान उपयोगकर्ता स्थिति का अर्थ यह नहीं है कि वह काम कर रहा है या यदि उपयोगकर्ता की सिस्टम में कोई भूमिका नहीं है।
नीचे दिए गए सभी मॉडलों में, टेबल status
और role
वही हैं।
तालिका status
फ़ील्ड हैं id
और status_name
और विशेषता is_active
. यदि विशेषता is_active
. है "ट्रू" पर सेट है, इसका मतलब है कि जिस उपयोगकर्ता की स्थिति है वह वर्तमान में काम कर रहा है। उदाहरण के लिए, "काम कर रहे" स्थिति में is_active
. विशेषता होगी ट्रू के मान के साथ, जबकि अन्य ("छुट्टी पर", "बीमार अवकाश पर", "अनुबंध समाप्त") का मान गलत होगा।
भूमिका तालिका में केवल दो फ़ील्ड हैं:id
और role_name
।
user_account
तालिका user_account
इस लेख में प्रस्तुत तालिका। केवल पहले मॉडल में user_account
तालिका में दो अतिरिक्त विशेषताएं हैं (role_id
और status_id
)।
कुछ मॉडल पेश किए जाएंगे। वे सभी काम करते हैं और इस्तेमाल किए जा सकते हैं लेकिन उनके फायदे और नुकसान हैं।
साधारण मॉडल
पहला विचार यह हो सकता है कि हम केवल user_account
तालिका, तालिकाओं पर संदर्भित status
और role
. दोनों role_id
और status_id
अनिवार्य हैं।
यह डिज़ाइन करने के लिए और प्रश्नों के साथ डेटा को संभालने के लिए बहुत आसान है लेकिन इसके कुछ नुकसान हैं:
-
हम कोई इतिहास (या भविष्य) डेटा नहीं रखते हैं।
जब हम स्थिति या भूमिका बदलते हैं तो हम बस
status_id
. को अपडेट कर देते हैं औरrole_id
user_account
टेबल। यह अभी के लिए ठीक काम करेगा, इसलिए जब हम कोई बदलाव करेंगे तो यह सिस्टम में दिखाई देगा। यह ठीक है अगर हमें यह जानने की जरूरत नहीं है कि ऐतिहासिक रूप से स्थितियां और भूमिकाएं कैसे बदल गई हैं। साथ ही इसमें एक समस्या है कि हम भविष्य नहीं जोड़ सकते इस मॉडल में अतिरिक्त तालिकाओं को जोड़े बिना भूमिका या स्थिति। एक स्थिति जहां हम शायद उस विकल्प को रखना चाहेंगे, जब हम जानते हैं कि कोई व्यक्ति अगले सोमवार से छुट्टी पर होगा। एक और उदाहरण है जब हमारे पास एक नया कर्मचारी होता है; हो सकता है कि हम अभी उसकी स्थिति और भूमिका दर्ज करना चाहते हैं और भविष्य में किसी बिंदु पर इसे वैध बनाना चाहते हैं।हमारे पास शेड्यूल इवेंट . होने की स्थिति में भी एक जटिलता है जो भूमिकाओं और स्थितियों का उपयोग करते हैं। अगले कार्य दिवस के लिए डेटा तैयार करने वाले ईवेंट आमतौर पर चलते हैं, जबकि अधिकांश उपयोगकर्ता सिस्टम का उपयोग नहीं करते हैं (जैसे रात के समय)। तो अगर कोई कल काम नहीं करेगा तो हमें वर्तमान दिन के अंत तक इंतजार करना होगा और फिर उसकी भूमिका और स्थिति को उचित रूप में बदलना होगा। उदाहरण के लिए, यदि हमारे पास ऐसे कर्मचारी हैं जो वर्तमान में काम करते हैं और "कॉल सेंटर कर्मचारी" की भूमिका निभाते हैं, तो उन्हें उन ग्राहकों की एक सूची मिलेगी जिन्हें उन्हें कॉल करना है। अगर गलती से किसी के पास वह दर्जा और भूमिका थी तो उसे अपने ग्राहक भी मिल जाएंगे और हमें इसे ठीक करने में समय लगाना होगा।
-
उपयोगकर्ता की एक समय में केवल एक ही भूमिका हो सकती है।
आम तौर पर उपयोगकर्ताओं को एक से अधिक भूमिकाएं करने में सक्षम होना चाहिए प्रणाली में। हो सकता है कि जिस समय आप डेटाबेस डिजाइन कर रहे हों, उस समय ऐसा कुछ करने की आवश्यकता न हो। ध्यान रखें कि कार्यप्रवाह/प्रक्रिया में परिवर्तन हो सकते हैं। उदाहरण के लिए, किसी समय क्लाइंट दो भूमिकाओं को एक में मिलाने का निर्णय ले सकता है। एक संभावित समाधान यह है कि एक नई भूमिका बनाई जाए और पिछली भूमिकाओं से सभी कार्यात्मकताओं को उसमें असाइन किया जाए। दूसरा समाधान (यदि उपयोगकर्ताओं की एक से अधिक भूमिकाएँ हो सकती हैं) यह होगा कि क्लाइंट केवल उन उपयोगकर्ताओं को दोनों भूमिकाएँ प्रदान करता है जिनकी उन्हें आवश्यकता होती है। बेशक, दूसरा समाधान अधिक व्यावहारिक है और क्लाइंट को सिस्टम को उसकी जरूरतों के लिए तेजी से समायोजित करने की क्षमता देता है (जो इस मॉडल द्वारा समर्थित नहीं है)।
दूसरी ओर, इस मॉडल का दूसरों पर एक बड़ा फायदा भी है। यह आसान है और इसलिए स्थितियों और भूमिकाओं को बदलने के लिए प्रश्न भी सरल होंगे। साथ ही, एक क्वेरी जो यह जांचती है कि उपयोगकर्ता के पास सिस्टम में लॉगिन करने का अधिकार है या नहीं, अन्य मामलों की तुलना में बहुत आसान है:
select user_account.id, user_account.role_id from user_account left join status on user_account.status_id = status.id where status.is_user_working = True and user_account.user_name = @user_name and user_account.password_hash_algorithm = @password;
@user_name और @password एक इनपुट फॉर्म के वेरिएबल हैं, जबकि क्वेरी उपयोगकर्ता की आईडी और उसके पास मौजूद role_id लौटाती है। ऐसे मामलों में जब user_name या पासवर्ड मान्य नहीं होते हैं, user_name और पासवर्ड की जोड़ी मौजूद नहीं है, या उपयोगकर्ता के पास एक नियत स्थिति है जो सक्रिय नहीं है, तो क्वेरी कोई परिणाम नहीं देगी। इस तरह हम लॉगिन को मना कर सकते हैं।
इस मॉडल का उपयोग उन मामलों में किया जा सकता है जब:
- हमें यकीन है कि प्रक्रिया में कोई बदलाव नहीं होगा जिसके लिए उपयोगकर्ताओं को एक से अधिक भूमिकाएं निभानी होंगी
- हमें इतिहास में भूमिकाओं/स्थिति परिवर्तनों को ट्रैक करने की आवश्यकता नहीं है
- हमें अधिक भूमिका/स्थिति प्रशासन की अपेक्षा नहीं है।
समय घटक जोड़ा गया
यदि हमें किसी उपयोगकर्ता की भूमिका और स्थिति इतिहास को ट्रैक करने की आवश्यकता है तो हमें user_account
और role
और user_account
और status
. बेशक हम role_id
को हटा देंगे और status_id
user_account
टेबल। मॉडल में नई तालिकाएं हैं user_has_role
और user_has_status
और उनमें सभी फ़ील्ड, समाप्ति समय को छोड़कर, अनिवार्य हैं।
तालिका user_has_role
इसमें उन सभी भूमिकाओं के बारे में डेटा होता है जो उपयोगकर्ताओं के पास सिस्टम में थीं। वैकल्पिक कुंजी है (user_account_id
, role_id
, role_start_time
) क्योंकि उपयोगकर्ता को एक ही समय में एक ही भूमिका को एक से अधिक बार सौंपने का कोई मतलब नहीं है।
तालिका user_has_status
इसमें उन सभी स्थितियों के बारे में डेटा होता है जो उपयोगकर्ताओं के पास सिस्टम में थीं। यहां वैकल्पिक कुंजी है (user_account_id
, status_start_time
) क्योंकि एक उपयोगकर्ता के पास दो स्थितियां नहीं हो सकती हैं जो एक ही समय में शुरू होती हैं।
प्रारंभ समय शून्य नहीं हो सकता क्योंकि जब हम कोई नई भूमिका/स्थिति सम्मिलित करते हैं, तो हम जानते हैं कि यह किस क्षण से प्रारंभ होगा। अगर हमें नहीं पता कि भूमिका/स्थिति कब खत्म होगी (उदाहरण के लिए भूमिका कल से तब तक मान्य है जब तक कि भविष्य में कुछ न हो जाए) तो समाप्ति समय शून्य हो सकता है।
एक संपूर्ण इतिहास होने के अलावा, अब हम भविष्य में स्थितियाँ और भूमिकाएँ जोड़ सकते हैं। लेकिन यह जटिलताएं पैदा करता है क्योंकि जब हम कोई इंसर्ट या अपडेट करते हैं तो हमें ओवरलैपिंग की जांच करनी होती है।
उदाहरण के लिए, उपयोगकर्ता के पास एक समय में केवल एक ही स्थिति हो सकती है। इससे पहले कि हम एक नई स्थिति डालें, हमें डेटाबेस में उस उपयोगकर्ता के लिए सभी मौजूदा स्थितियों के साथ एक नई स्थिति के प्रारंभ समय और समाप्ति समय की तुलना करनी होगी। हम इस तरह की क्वेरी का उपयोग कर सकते हैं:
select * from user_has_status where user_has_status.user_account_id = @user_account_id and ( # test if @start_time included in interval of some previous status (user_has_status.status_start_time <= @start_time and ifnull(user_has_status.status_end_time, "2200-01-01") >= @start_time) or # test if @end_time included in interval of some previous status (user_has_status.status_start_time <= @end_time and ifnull(user_has_status.status_end_time, "2200-01-01") >= ifnull(@end_time, "2199-12-31")) or # if @end_time is null we cannot have any statuses after @start_time (@end_time is null and user_has_status.status_start_time >= @start_time) or # new status "includes" old satus (@start_time <= user_has_status.status_start_time <= @end_time) (user_has_status.status_start_time >= @start_time and user_has_status.status_start_time <= ifnull(@end_time, "2199-12-31")) )
@start_time
और @end_time
वे चर हैं जिनमें उस स्थिति का प्रारंभ समय और समाप्ति समय होता है जिसे हम सम्मिलित करना चाहते हैं और @user_account_id
उपयोगकर्ता आईडी है जिसके लिए हम इसे सम्मिलित करते हैं। @end_time
शून्य हो सकता है और हमें इसे क्वेरी में संभालना होगा। इस उद्देश्य के लिए, शून्य मानों का परीक्षण ifnull()
. के साथ किया जाता है समारोह। यदि मान शून्य है, तो एक उच्च दिनांक मान असाइन किया जाता है (इतना अधिक कि जब कोई क्वेरी में कोई त्रुटि नोटिस करता है तो हम लंबे समय तक चले जाएंगे :)। क्वेरी मौजूदा स्थितियों के प्रारंभ समय और समाप्ति समय की तुलना में एक नई स्थिति के लिए प्रारंभ समय और समाप्ति समय के सभी संयोजनों की जांच करती है। यदि क्वेरी कोई रिकॉर्ड लौटाती है, तो हमारे पास मौजूदा स्थितियों के साथ अतिव्यापी है और हमें नई स्थिति डालने से मना करना चाहिए। साथ ही एक कस्टम त्रुटि उठाना अच्छा होगा।
यदि हम वर्तमान भूमिकाओं और स्थितियों (उपयोगकर्ता अधिकार) की सूची की जांच करना चाहते हैं तो हम केवल प्रारंभ समय और समाप्ति समय का उपयोग करके परीक्षण करते हैं।
select user_account.id, user_has_role.id from user_account left join user_has_role on user_has_role.user_account_id = user_account.id left join user_has_status on user_account.id = user_has_status.user_account_id left join status on user_has_status.status_id = status.id where user_account.user_name = @user_name and user_account.password_hash_algorithm = @password and user_has_role.role_start_time <= @time and ifnull(user_has_role.role_end_time,"2200-01-01") >= @time and user_has_status.status_start_time <= @time and ifnull(user_has_status.status_end_time,"2200-01-01") >= @time and status.is_user_working = True
@user_name
और @password
@time
. के दौरान इनपुट फॉर्म से वेरिएबल हैं अब() पर सेट किया जा सकता है। जब कोई उपयोगकर्ता लॉगिन करने का प्रयास करता है तो हम उस समय उसके अधिकारों की जांच करना चाहते हैं। परिणाम उन सभी भूमिकाओं की एक सूची है जो उपयोगकर्ता के पास सिस्टम में उपयोगकर्ता_नाम और पासवर्ड के मेल खाने की स्थिति में होती है और उपयोगकर्ता की वर्तमान में सक्रिय स्थिति होती है। यदि उपयोगकर्ता के पास एक सक्रिय स्थिति है लेकिन कोई भूमिका निर्दिष्ट नहीं है, तो क्वेरी कुछ भी वापस नहीं करेगी।
यह प्रश्न खंड 3 की तुलना में सरल है और यह मॉडल हमें स्थितियों और भूमिकाओं का इतिहास रखने में सक्षम बनाता है। इसके अलावा, हम भविष्य के लिए स्थितियों और भूमिकाओं का प्रबंधन कर सकते हैं और सब कुछ ठीक काम करेगा।
अंतिम मॉडल
यह सिर्फ एक विचार है कि अगर हम प्रदर्शन में सुधार करना चाहते हैं तो पिछले मॉडल को कैसे बदला जा सकता है। चूंकि एक उपयोगकर्ता के पास एक समय में केवल एक सक्रिय स्थिति हो सकती है, इसलिए हम status_id
. जोड़ सकते हैं user_account
तालिका (current_status_id
) इस तरह, हम उस विशेषता के मूल्य का परीक्षण कर सकते हैं और हमें user_has_status
टेबल। संशोधित क्वेरी इस तरह दिखेगी:
select user_account.id, user_has_role.id from user_account left join user_has_role on user_has_role.user_account_id = user_account.id left join status on user_account.current_status_id = status.id where user_account.user_name = @user_name and user_account.password_hash_algorithm = @password and user_has_role.role_start_time <= @time and ifnull(user_has_role.role_end_time,"2200-01-01") >= @time and status.is_user_working = True
जाहिर है यह क्वेरी को सरल करता है और बेहतर प्रदर्शन की ओर ले जाता है लेकिन एक बड़ा मुद्दा है जिसे हल करने की आवश्यकता होगी। current_status_id
user_account
तालिका की जाँच की जानी चाहिए और यदि आवश्यक हो तो निम्नलिखित स्थितियों में बदल दी जानी चाहिए:
user_has_status
टेबल- एक निर्धारित कार्यक्रम में हर दिन हमें जांचना चाहिए कि क्या किसी की स्थिति बदल गई है (वर्तमान में सक्रिय स्थिति समाप्त हो गई है या/और कुछ भविष्य की स्थिति सक्रिय हो गई है) और तदनुसार इसे अपडेट करें
उन मानों को सहेजना बुद्धिमानी होगी जिनका उपयोग क्वेरीज़ अक्सर करेंगी। इस तरह हम एक ही चेक को बार-बार करने और नौकरी को विभाजित करने से बचेंगे। यहां हम user_has_status
तालिका और हम current_status_id
. पर परिवर्तन करेंगे केवल जब वे होते हैं (सम्मिलित/अपडेट/डिलीट) या जब सिस्टम इतना अधिक उपयोग में नहीं होता है (अनुसूचित ईवेंट आमतौर पर तब चलते हैं जब अधिकांश उपयोगकर्ता सिस्टम का उपयोग नहीं करते हैं)। हो सकता है कि इस मामले में हमें current_status_id
लेकिन इसे एक ऐसे विचार के रूप में देखें जो समान परिस्थितियों में मदद कर सकता है।