On Basic Authentication of node express, I need to pass an extra parameter to node express callback, that parameter is role. That role parameter is akin to Authorize attribute of ASP.NET MVC.
Here's a rough signature of node express callback:
interface Func { (random: number, basicAuthUser: string) : boolean; } function doSomething(...actions: Func[]) : void { var basicAuthUser = "davegrohl"; // obtained from browser's Basic Authentication for(var i = 0; i < actions.length; ++i) { var a = actions[i]; var okToContinue = a(Math.random() * 100, basicAuthUser); if (!okToContinue) break; } } console.log(''); console.log('without authorization'); doSomething( (i,u) => { console.log('Alpha ' + i); return true; }, (i,u) => { console.log('Beta ' + i); return true; } );
Then I think, authentication and authorization role mechanism could be slotted on the first parameter of the array. But how would I pass an extra parameter on the callback? Then an enlightenment from C# came. On C# object, the properties can be accessed even if the method reference is passed to callback. The solution could be written in C# like the following:
Live Code: https://dotnetfiddle.net/tSenYK
using System; using System.Linq; public class Program { public static void Main() { Console.WriteLine("Without authorization:"); DoSomething( (i,u) => { Console.WriteLine("Alpha " + i); return true; }, (i,u) => { Console.WriteLine("Beta " + i); return true; } ); Console.WriteLine(); Console.WriteLine("Rockstar activity:"); DoSomething( new Authorizer("rockstar").ActionToDo, // just pass the reference of method (i,u) => { Console.WriteLine("Alpha " + i); return true; }, (i,u) => { Console.WriteLine("Beta " + i); return true; } ); Console.WriteLine(); Console.WriteLine("Guest activity:"); DoSomething( new Authorizer("guest").ActionToDo, (i,u) => { Console.WriteLine("Alpha " + i); return true; }, (i,u) => { Console.WriteLine("Beta " + i); return true; } ); } // third-party framework. cannot change the signature public static void DoSomething(params Func<int, string, bool>[] actions) { var basicAuthUser = "davegrohl"; // obtained from browser's Basic Authentication for(int i = 0; i < actions.Length; ++i) { var a = actions[i]; bool okToContinue = a(new Random().Next(10), basicAuthUser); if (!okToContinue) break; } } } class Authorizer { public string RoleAllowed { get; set; } public Authorizer(string roleAllowed) { this.RoleAllowed = roleAllowed; } string GetRole(string basicAuthUser) { return "rockstar"; // davegrohl's role fetched from database } public bool ActionToDo(int i, string basicAuthUser) { // Database operation here. // Get the role of basicAuthUser var role = this.GetRole(basicAuthUser); return role == this.RoleAllowed; } }
Output: Without authorization: Alpha 4 Beta 4 Rockstar activity: Alpha 4 Beta 4 Guest activity:
So I just need write the equivalent in TypeScript/JavaScript:
Live Code at TypeScriptLang
class Authorizer { roleAllowed : string; constructor(roleAllowed: string) { this.roleAllowed = roleAllowed; } private getRole(basicAuthUser: string) : string { return "rockstar"; // davegrohl's role fetched from database } actionToDo(i: number, basicAuthUser: string) : boolean { // Database operation here. // Get the role of basicAuthUser var role = this.getRole(basicAuthUser); // davegrohl's role fetched from database return role === this.roleAllowed; } } interface Func { (random: number, basicAuthUser: string) : boolean; } function doSomething(...actions: Func[]) : void { var basicAuthUser = "davegrohl"; // obtained from browser's Basic Authentication for(var i = 0; i < actions.length; ++i) { var a = actions[i]; var okToContinue = a(Math.random() * 100, basicAuthUser); if (!okToContinue) break; } } console.log(''); console.log('without authorization'); doSomething( (i,u) => { console.log('Alpha ' + i); return true; }, (i,u) => { console.log('Beta ' + i); return true; } ); console.log(''); console.log("Rockstar activity:"); doSomething( new Authorizer("rockstar").actionToDo, (i,u) => { console.log("Alpha " + i); return true; }, (i,u) => { console.log("Beta " + i); return true; } ); console.log(''); console.log("Guest activity:"); doSomething( new Authorizer("guest").actionToDo, (i,u) => { console.log("Alpha " + i); return true; }, (i,u) => { console.log("Beta " + i); return true; } );
However, it didn't work. The this object looks like it's not an instance af Authorizer class. The error says:
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBpD9VYwUnZejMfunIJsn8L7Y6Nfc1LFhsD85epCpjUjJS5qgasytBUgyjeVPS6-gtIDw9qaNBClWGLTCh22mvhhgqcTIPfZX3piPKNlvW2BQwkyU0zer79DY3dbe4OTjJ-EOMf_3iMQtE/s1600/node-incorrect-this.png)
Then I add a console.log of the this object.
actionToDo(i: number, basicAuthUser: string) : boolean { // Database operation here. // Get the role of basicAuthUser console.log(this); var role = this.getRole(basicAuthUser); // davegrohl's role fetched from database return role === this.roleAllowed; }
Here's the output, oops it looks like the this object is not carried when passing the reference of the method to callbacks.
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgg4MGPorXgw6fI6DEf6HkcGPNmf-e4sHGRlw0IPVGAcNp_EKVwAGXa5Vl3nNX0K2zh8MGkBGrbWWv3JcSv8w-gyVQeycXxCKygf2tyrkT5596bO3PQhGxHabmPZdaNOLICPxf63OsgU8kR/s1600/node-incorrect-this-logged.png)
To make the long story short, the this object is not included when accessing the reference of the method. Not similar to C#
The solution is to bind the this object before passing the reference of the method to callback.
Correct:
Live Code at TypeScriptLang
class Authorizer { roleAllowed : string; constructor(roleAllowed: string) { this.roleAllowed = roleAllowed; } getBindedActionToDo() : Func { return this.actionToDo.bind(this); } private getRole(basicAuthUser: string) : string { return "rockstar"; // davegrohl's role fetched from database } actionToDo(i: number, basicAuthUser: string) : boolean { // Database operation here. // Get the role of basicAuthUser console.log(this); var role = this.getRole(basicAuthUser); // davegrohl's role fetched from database return role === this.roleAllowed; } } interface Func { (random: number, basicAuthUser: string) : boolean; } function doSomething(...actions: Func[]) : void { var basicAuthUser = "davegrohl"; // obtained from browser's Basic Authentication for(var i = 0; i < actions.length; ++i) { var a = actions[i]; var okToContinue = a(Math.random() * 100, basicAuthUser); if (!okToContinue) break; } } console.log(''); console.log('without authorization'); doSomething( (i,u) => { console.log('Alpha ' + i); return true; }, (i,u) => { console.log('Beta ' + i); return true; } ); console.log(''); console.log("Rockstar activity:"); doSomething( new Authorizer("rockstar").getBindedActionToDo(), (i,u) => { console.log("Alpha " + i); return true; }, (i,u) => { console.log("Beta " + i); return true; } ); console.log(''); console.log("Guest activity:"); doSomething( new Authorizer("guest").getBindedActionToDo(), (i,u) => { console.log("Alpha " + i); return true; }, (i,u) => { console.log("Beta " + i); return true; } );
Output:
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbvEifk0YMnRbYxlZre2UMcSgF9Im_x8PNA18-LZoTf4LHlVHKuTTiU48qKhiyFbUoIgvFSQdtG7bnNRcZyKuda25ePyi6dujt-_9RdWXZ2Nt4eA9zsnU3DenegawiQYK5ryx1-5xhZ27-/s320/node-correct.png)
Happy Coding!
No comments:
Post a Comment