I am working with loopback interceptor to use its value in the controller function.
from the moment I implemented interceptor is all i know that every user requests have different instance of interceptor.
here is my code for intercepting token
export class ExtractTokenInterceptor implements Provider<Interceptor> {
constructor() { }
value(): Interceptor {
return this.intercept.bind(this);
}
async intercept<T>(
invocationCtx: InvocationContext,
next: () => ValueOrPromise<T>,
) {
const req: any = await
invocationCtx.get(RestBindings.Http.REQUEST, {
optional: true,
});
// const req: any = await invocationCtx.parent.get(RestBindings.Http.REQUEST, { optional: true });
const authorization = req.headers.hasOwnProperty('authorization') ? req.headers.authorization : null;
const userName = req.headers.hasOwnProperty('x-username') ? req.headers['x-username'] : null;
const token = authorization ? req.headers.authorization.split(' ')[1] : null;
const referer = req.headers.referer;
const clientIp = req.headers['x-forwarded-for'];
invocationCtx.targetClass.prototype.token = token;
invocationCtx.targetClass.prototype.referer = referer;
invocationCtx.targetClass.prototype.clientIp = clientIp;
invocationCtx.targetClass.prototype.userName = userName;
if(invocationCtx.targetClass.prototype.jwt) {
console.log('ERROR! INTERCEPTOR HAS VALUE', invocationCtx.targetClass.prototype.jwt);
}
if (token) {
const decodedJwt = jwtDecode(token);
console.log(invocationCtx.targetClass.prototype.jwt);
invocationCtx.targetClass.prototype.jwt = decodedJwt;
const loopCnt = 20;
if(decodedJwt.preferred_username === 'user1') {
let a = 0;
const timeout = (ms) => {
return new Promise(resolve => setTimeout(resolve, ms));
}
while (a < loopCnt) { // i will delay the interceptor for specific user
await timeout(1000);
console.log('['+a+'] user is', invocationCtx.targetClass.prototype.jwt.preferred_username);
invocationCtx.targetClass.prototype.counter = a++;
}
}
}
const result = await next();
return result;
}
}
What happen here is this. I have two user named user1 and user2.
both user is logged in. both user will trigger a specific endpoint
if you can see in my interceptor, i put a delay in user1 interceptor.
i will print the current interceptor value base on the token.
then if user2 will trigger the same end point, while the interceptor of user1 is not yet finished, i can see the print for user1 will be changed by user2.
take a look at the code that i only put delay for user1 only so user2 can proceed to controller function
i cant find any solution from loopback why interceptor is using one instance per endpoint
The problem is that you are assigning the data in the
prototypeof thetargetClass, which is causing issues with concurrency since the prototype is naturally shared across all instances of the class.So when multiple requests are made, they will try to modify the same prototype object.
To solve this you can bind token, referrer etc. in the
invocationCtxinstead.Quoting a code snippet from interceptors test cases that shows how can you bind and use those value in your class: