
किसी बिंदु पर एक एप्लिकेशन को प्राधिकरण की आवश्यकता होती है। इसका मतलब है कि पहुंच के विभिन्न स्तर एक वेब साइट पर (या किसी भी चीज़ के लिए) अलग तरीके से व्यवहार करते हैं। यह डेटा देखने से लेकर पूरे क्षेत्रों तक कुछ भी हो सकता है जो उपयोगकर्ताओं के एक समूह के लिए पहुंच योग्य नहीं हैं।
गैर-सिंगल पेज एप्लिकेशन (SPA) में, एक claim या role डेटा या एप्लिकेशन के एक क्षेत्र के साथ जुड़ा होता है, या तो उपयोगकर्ता के पास यह role या claim है या नहीं है। SPA में यह वही है, लेकिन एक बड़े अस्वीकरण के साथ। एक SPA ब्राउज़र में डाउनलोड होता है। इस बिंदु पर ब्राउज़र का कोड पर पूरा नियंत्रण होता है। एक दुर्भावनापूर्ण व्यक्ति कोड को अपनी इच्छा के अनुसार बदल सकता है।
क्योंकि SPAs को सुरक्षित नहीं किया जा सकता, SPA में प्रमाणीकरण और प्राधिकरण केवल उपयोगकर्ता अनुभव है। सभी सार्थक सुरक्षा वेब सर्वर पर की जानी चाहिए। यह लेख आपके API को हमलों से सुरक्षित करने को कवर नहीं करता। मैं Pluralsight से एक वीडियो देखने या आपकी सर्वर तकनीक के लिए सुरक्षा को संबोधित करने वाला एक पेपर पढ़ने की सिफारिश करता हूं।
इस लेख का उद्देश्य आपको दिखाना है कि मैंने अपने Angular 1.x SPA में एक प्राधिकरण उपयोगकर्ता अनुभव कैसे जोड़ा।
सुरक्षा स्कोप
मैंने UI के 3 क्षेत्रों की पहचान की है जिन्हें प्राधिकरण की आवश्यकता है: Elements (HTML), Routes, और Data।
बस एक अनुस्मारक, SPA को सुरक्षित करना सर्वर को सुरक्षित करने का विकल्प नहीं है। क्लाइंट पर अनुमतियां केवल ईमानदार लोगों को ईमानदार रखने और उपयोगकर्ता को एक अच्छा अनुभव प्रदान करने के लिए हैं।
विस्तार से 3 क्षेत्र:
Elements
आपको विशिष्ट HTML elements को छुपाना होगा। यह एक label, डेटा के साथ एक table, एक button, या पेज पर कोई भी element हो सकता है।
Routes
आप पूरे routes को छुपाना चाहेंगे। कुछ मामलों में आप नहीं चाहते कि उपयोगकर्ता एक view तक पहुंच सके। route को सुरक्षित करके एक उपयोगकर्ता view पर navigate नहीं कर सकता। इसके बजाय उन्हें “आप इस view पर navigate करने के लिए अधिकृत नहीं हैं” संदेश दिखाया जाएगा।
Data
कभी-कभी view में elements को छुपाना पर्याप्त नहीं होता। एक चतुर उपयोगकर्ता बस source देख सकता है और HTML source में छुपे हुए डेटा को देख सकता है या इसे ब्राउज़र में stream होते देख सकता है। हम चाहते हैं कि डेटा पहली जगह में retrieve न हो।
सुरक्षा जोड़ना मुश्किल है। पहले मैंने HTTP API (क्लाइंट पर) पर पहुंच को सीमित करने की कोशिश की। मैंने जल्दी महसूस किया कि यह काम नहीं करेगा। एक उपयोगकर्ता के पास डेटा तक प्रत्यक्ष पहुंच नहीं हो सकती, लेकिन इसका मतलब यह नहीं है कि उनके पास डेटा तक अप्रत्यक्ष पहुंच नहीं है। HTTP API layer पर (आमतौर पर एप्लिकेशन में सबसे निचली में से एक) हम कॉल के संदर्भ को नहीं बता सकते और इसलिए इसमें सुरक्षा चिंताओं को लागू नहीं कर सकते।
नीचे मैंने कोडिंग नमूने प्रदान किए हैं:
Code
मैंने प्राधिकरण जांच कोड के लिए एक service बनाई। यह प्राधिकरण का दिल है। सभी प्राधिकरण अनुरोध इस service का उपयोग करके जांचते हैं कि उपयोगकर्ता विशेष कार्य के लिए अधिकृत है या नहीं।
angular.module('services')
.service('AuthorizationContext',function(_, Session){
this.authorizedExecution = function(key, action){
//Looking for the claim key that was passed in. If it exists in the claim set, then execute the action.
Session.claims(function(claims){
var claim = findKey(key, claims);
//If Claim was found then execute the call.
//If it was not found, do nothing
if(claim !== undefined){
action();
}
});
};
this.authorized = function(key, callback){
//Looking for the claim key that was passed in. If it exists in the claim set, then execute the action.
Session.claims(function(claims){
var claim = findKey(key, claims);
//If they don't have any security key, then move forward and authorization.
var valid = claim !== undefined;
callback(valid);
});
};
//this.agencyViewKey = '401D91E7-6EA0-46B4-9A10-530E3483CE15';
function findKey(key, claims){
var claim = _.find(claims, function(item){
return item.value === key;
});
return claim;
}
});
Authorize Directive
authorize directive को किसी भी HTML element पर लागू किया जा सकता है जिसे आप विशिष्ट स्तर की पहुंच के बिना उपयोगकर्ताओं से छुपाना चाहते हैं। यदि उपयोगकर्ता के पास उनके claims के हिस्से के रूप में access token है तो उन्हें element देखने की अनुमति है। यदि उनके पास नहीं है तो यह उनसे छुपा हुआ है।
angular.module('directives')
.directive('authorize', ['$compile', 'AuthorizationContext', function($compile, AuthorizationContext) {
return {
restrict: 'A',
replace: true,
//can't have isolated the scope in a shared directive
link:function ($scope, element, attributes) {
var securityKey = attributes.authorize;
AuthorizationContext.authorized(securityKey, function(authorized){
var el = angular.element(element);
el.attr('ng-show', authorized);
//remove the attribute, otherwise it creates an infinite loop.
el.removeAttr('authorize');
$compile(el)($scope);
});
}
};
}]);
Elements
मैं अपने एप्लिकेशन में tabs पर बहुत निर्भर करता हूं। मैं authorize directive को उस tab पर लागू करता हूं जिसे मैं उचित claims के बिना उपयोगकर्ताओं से छुपाना चाहता हूं।
<tabset>
<tab ng-cloak heading="Users" authorize="{{allowUserManagement}}">
...html content
</tab>
</tabset>
Routes
मैं ui-router
का उपयोग कर रहा हूं। दुर्भाग्य से जो लोग नहीं हैं, उनके लिए मेरे पास out of the box AngularJS router के लिए कोड नहीं है।
$stateChangeStart
में मैं route को authenticate करता हूं। यह उस event में कोड है।
$rootScope.$on("$stateChangeStart", function(event, toState, toParams, fromState, fromParams){
AuthenticationManager.authenticate(event, toState, toParams);
});
वह function जो route को authorize करता है। यदि यह authorized है, तो route को जारी रखने की अनुमति है। यदि यह authorized नहीं है, तो उपयोगकर्ता को एक संदेश दिखाया जाता है और उन्हें home page पर भेज दिया जाता है।
function authorizedRoute(toState, location, toaster, breadCrumbs){
if(toState.authorization !== undefined){
AuthorizationContext.authorized(toState.authorization, function(authorized){
if(!authorized){
toaster.pop('error', 'Error', 'You are not authorized to view this page.');
location.path("/search");
} else {
breadCrumbs();
}
});
} else{
breadCrumbs();
}
}
इस router definition में आप ‘authorization’ नामक एक property देखेंगे। यदि उपयोगकर्ता के पास यह claim है तो उन्हें आगे बढ़ने की अनुमति है।
angular.module('agency',
[
'ui.router',
'services'
])
.config(function config($stateProvider){
$stateProvider.state( 'agency', {
url: '/agency',
controller: 'agency.index',
templateUrl: 'agency/agency.tpl.html',
authenticate: true,
authorization:'401d91e7-6ea0-46b4-9a10-530e3483ce15',
data:{ pageTitle: 'Agency' }
});
});
Data
कुछ मामलों में, आप डेटा के लिए सर्वर से request नहीं करना चाहते। यदि उपयोगकर्ता के पास claim है तो उन्हें request करने की अनुमति होगी।
लेख की शुरुआत में ऊपर दिया गया AuthorizationContext
authoriedExecution
के लिए कोड दिखाता है। यहां आप इसका उपयोग देखते हैं।
AuthorizationContext.authorizedExecution(Keys.authorization.allowUserManagement, function(){
//execute code, if the loggedin user has rights.
});
जैसा कि मैंने ऊपर उल्लेख किया है, यह सर्वर को सुरक्षित करने का विकल्प नहीं है। यह कोड एक अद्भुत उपयोगकर्ता अनुभव प्रदान करने के लिए काम करता है।
लेखक: चक कॉनवे सॉफ्टवेयर इंजीनियरिंग और जेनेरेटिव AI में विशेषज्ञता रखते हैं। उनसे सोशल मीडिया पर जुड़ें: X (@chuckconway) या उन्हें YouTube पर देखें।