Last active
October 23, 2020 16:56
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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] | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
}; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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' }); | |
}); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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