
কোনো একটি সময়ে একটি অ্যাপ্লিকেশনের অনুমোদনের প্রয়োজন হয়। এর মানে হলো বিভিন্ন স্তরের অ্যাক্সেস একটি ওয়েব সাইটে (বা যেকোনো বিষয়ের জন্য) ভিন্নভাবে আচরণ করে। এটি ডেটা দেখা থেকে শুরু করে সম্পূর্ণ এলাকা পর্যন্ত হতে পারে যা ব্যবহারকারীদের একটি গ্রুপের জন্য অ্যাক্সেসযোগ্য নয়।
নন-সিঙ্গেল পেজ অ্যাপ্লিকেশনে (SPA), একটি claim বা role ডেটা বা অ্যাপ্লিকেশনের একটি এলাকার সাথে যুক্ত থাকে, হয় ব্যবহারকারীর এই role বা claim আছে অথবা নেই। একটি SPA-তে এটি একই, কিন্তু একটি বিশাল দাবিত্যাগের সাথে। একটি SPA ব্রাউজারে ডাউনলোড হয়। এই মুহূর্তে ব্রাউজারের কোডের উপর সম্পূর্ণ নিয়ন্ত্রণ রয়েছে। একজন দুষ্ট ব্যক্তি কোড পরিবর্তন করে তার ইচ্ছামতো কাজ করাতে পারে।
যেহেতু SPA গুলো সুরক্ষিত করা যায় না, একটি SPA-তে authentication এবং authorization কেবলমাত্র ব্যবহারকারীর অভিজ্ঞতা। সমস্ত অর্থবহ নিরাপত্তা অবশ্যই ওয়েব সার্ভারে করতে হবে। এই নিবন্ধটি আক্রমণের বিরুদ্ধে আপনার API সুরক্ষিত করার বিষয়ে আলোচনা করে না। আমি Pluralsight থেকে একটি ভিডিও দেখার বা আপনার সার্ভার প্রযুক্তির জন্য নিরাপত্তা সম্বোধনকারী একটি পেপার পড়ার সুপারিশ করি।
এই নিবন্ধের উদ্দেশ্য হলো আমি কীভাবে আমার Angular 1.x SPA-তে একটি authorization ব্যবহারকারী অভিজ্ঞতা যোগ করেছি তা দেখানো।
নিরাপত্তা স্কোপ
আমি UI-এর 3টি এলাকা চিহ্নিত করেছি যার authorization প্রয়োজন: 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-এ (সাধারণত অ্যাপ্লিকেশনের সবচেয়ে নিম্ন স্তরের একটি) আমরা call-এর context বলতে পারি না এবং তাই এতে নিরাপত্তা বিষয়গুলি প্রয়োগ করতে পারি না।
নিচে আমি কোডিং নমুনা প্রদান করেছি:
কোড
আমি authorization checking কোডের জন্য একটি service তৈরি করেছি। এটি authorization-এর হৃদয়। সমস্ত authorization অনুরোধ এই 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-এর অংশ হিসেবে অ্যাক্সেস টোকেন থাকে তাহলে তারা 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-এর উপর অনেক নির্ভর করি। আমি সেই tab-এ authorize directive প্রয়োগ করি যা আমি যথাযথ 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
কিছু ক্ষেত্রে, আপনি ডেটার জন্য সার্ভারে অনুরোধ করতে চান না। যদি ব্যবহারকারীর claim থাকে তাহলে তাদের অনুরোধ করার অনুমতি দেওয়া হবে।
নিবন্ধের শুরুতে উপরের AuthorizationContext
authoriedExecution
-এর জন্য কোড দেখায়। এখানে আপনি এর ব্যবহার দেখতে পাচ্ছেন।
AuthorizationContext.authorizedExecution(Keys.authorization.allowUserManagement, function(){
//execute code, if the loggedin user has rights.
});
যেমনটি আমি উপরে উল্লেখ করেছি, এটি সার্ভার সুরক্ষিত করার বিকল্প নয়। এই কোড একটি চমৎকার ব্যবহারকারী অভিজ্ঞতা প্রদানের জন্য কাজ করে।
লেখক: চাক কনওয়ে সফটওয়্যার ইঞ্জিনিয়ারিং এবং জেনারেটিভ এআই-তে বিশেষজ্ঞ। তার সাথে সোশ্যাল মিডিয়ায় যোগাযোগ করুন: X (@chuckconway) অথবা তাকে YouTube-এ দেখুন।