Skip to content

Instantly share code, notes, and snippets.

@ondrej-kvasnovsky
Last active October 23, 2020 16:56
Show Gist options
  • Save ondrej-kvasnovsky/4cf5473490a52ac514da132df280537d to your computer and use it in GitHub Desktop.
Save ondrej-kvasnovsky/4cf5473490a52ac514da132df280537d to your computer and use it in GitHub Desktop.
NodeJS proxy/gateway using routing-controllers & axios, checking role permissions using Secured annotation
import 'reflect-metadata';
import axios, { AxiosRequestConfig, Method } from 'axios';
import { Body, createExpressServer, Get, JsonController, Post, Put, Req, Res } from 'routing-controllers';
import { Request, Response } from 'express';
import { Secured } from './Secured';
@JsonController()
export class UserController {
// this would a private endpoint
@Get('/private-service/posts')
theOtherOne() {
return 'not done! never';
}
// this would a private endpoint
@Post('/private-service/posts-update')
withPost(@Body() user: any) {
return user;
}
// this would a private endpoint
@Put('/private-service/posts-put')
withPut(@Body() user: any) {
return user;
}
// public endpoint
@Put('/posts-put')
@Secured(['posts.update', 'admin.update'])
async putAllPosts(@Req() request: Request, @Body() body: any) {
const baseURL = 'http://localhost:3000/private-service';
try {
let config = {
method: request.method as Method,
url: request.url,
baseURL: baseURL,
headers: request.headers,
data: body,
params: request.params
};
let result = await axios.request(config);
return result.data;
} catch (error) {
console.error(error.message, error);
}
}
// public endpoint
@Post('/posts-update')
@Secured(['posts.update', 'admin.update'])
async updateAllPosts(@Req() request: Request, @Body() body: any) {
const baseURL = 'http://localhost:3000/private-service';
try {
let config = {
method: request.method as Method,
url: request.url,
baseURL: baseURL,
headers: request.headers,
data: body,
params: request.params
};
let result = await axios.request(config);
return result.data;
} catch (error) {
console.error(error.message, error);
}
}
// public endpoint
@Get('/posts')
@Secured(['posts.read', 'admin.read'])
async getAllPosts(@Req() request: Request) {
const baseURL = 'http://localhost:3000/private-service';
try {
let config = {
method: request.method as Method,
url: request.url,
baseURL: baseURL,
headers: request.headers,
data: request.body,
params: request.params
};
let result = await axios.request(config);
return result.data;
} catch (error) {
console.error(error.message, error);
}
}
}
export const app = createExpressServer({
controllers: [UserController]
});
import { HttpError as HE } from 'routing-controllers';
export class HttpError extends HE {
constructor(httpCode: number, message?: string, readonly data?: any) {
super(httpCode, message);
Object.setPrototypeOf(this, HttpError.prototype);
}
toJSON() {
return {
code: this.httpCode,
message: this.message,
data: this.data
};
}
}
import axios, { AxiosRequestConfig } from 'axios';
import { app } from './app';
describe('Secured', () => {
let server: any;
beforeAll(() => {
server = app.listen(3000);
});
afterAll(() => {
server.close();
});
it('calls get', async () => {
const response = await axios.get('http://localhost:3000/posts');
expect(response.data).toEqual('not done! never');
});
it('calls post', async () => {
const response = await axios.post('http://localhost:3000/posts-update', { something: 'a value' });
expect(response.data).toEqual({ something: 'a value' });
});
it('calls put', async () => {
const response = await axios.put('http://localhost:3000/posts-put', { something: 'a value' });
expect(response.data).toEqual({ something: 'a value' });
});
});
import { HttpError } from '../../../src';
export function Secured(permissions: string[]): Function {
return (target: Object, propertyKey: string, descriptor: PropertyDescriptor): PropertyDescriptor => {
const originalFunction = descriptor.value;
descriptor.value = async function(...args: any[]) {
console.log('Checking permissions...', permissions);
// TODO: check the permissions
const isAllowed = true;
if (!isAllowed) {
throw new HttpError(403, 'go away');
}
return originalFunction.apply(this, args);
};
return descriptor;
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment