Compare commits

...

8 Commits

Author SHA1 Message Date
d85c126c27 implementation details
ref #6
2020-11-27 21:24:55 +01:00
e29c0cb7a1 Merge branch 'main' into feature/authed-routes
# Conflicts:
#	src/app.ts
#	src/controllers/TrackController.ts
2020-11-27 21:19:58 +01:00
37baa4ea45 default to only jwt checking (empty @Authorized() )
ref #6
2020-11-27 21:18:42 +01:00
5f4aed2f02 fixed auth parsing
ref #6
2020-11-27 21:16:15 +01:00
cb5f5b9ecb debugging
ref #6
2020-11-27 20:15:48 +01:00
c15b650181 sample in TrackController
ref #6
2020-11-27 19:55:49 +01:00
e29d59ac02 move to module
ref #6 #4
2020-11-27 19:55:35 +01:00
d5c6c9238f sample implementation of authorizationChecker 2020-11-27 19:45:44 +01:00
4 changed files with 84 additions and 8 deletions

View File

@ -3,11 +3,15 @@ import * as dotenvSafe from "dotenv-safe";
import { createExpressServer } from "routing-controllers";
import consola from "consola";
import loaders from "./loaders/index";
import authchecker from "./authchecker";
import { ErrorHandler } from './middlewares/ErrorHandler';
dotenvSafe.config();
const PORT = process.env.APP_PORT || 4010;
const app = createExpressServer({
authorizationChecker: authchecker,
middlewares: [ErrorHandler],
development: process.env.NODE_ENV === "production",
cors: true,
routePrefix: "/api",

51
src/authchecker.ts Normal file
View File

@ -0,0 +1,51 @@
import * as jwt from "jsonwebtoken";
import { Action, HttpError } from "routing-controllers";
// -----------
const sampletoken = jwt.sign({
"permissions": {
"TRACKS": ["read", "update", "delete", "add"]
// "TRACKS": []
}
}, process.env.JWT_SECRET || "secretjwtsecret")
console.log(`sampletoken: ${sampletoken}`);
// -----------
const authchecker = async (action: Action, permissions: string | string[]) => {
let required_permissions = undefined
if (typeof permissions === "string") {
required_permissions = [permissions]
} else {
required_permissions = permissions
}
// const token = action.request.headers["authorization"];
const provided_token = action.request.query["auth"];
let jwtPayload = undefined
try {
jwtPayload = <any>jwt.verify(provided_token, process.env.JWT_SECRET || "secretjwtsecret");
} catch (error) {
throw new HttpError(401, "jwt_illegal")
}
if (jwtPayload.permissions) {
action.response.local = {}
action.response.local.jwtPayload = jwtPayload.permissions
required_permissions.forEach(r => {
const permission_key = r.split(":")[0]
const actual_accesslevel_for_permission = jwtPayload.permissions[permission_key]
const permission_access_level = r.split(":")[1]
if (actual_accesslevel_for_permission.includes(permission_access_level)) {
return true;
} else {
throw new HttpError(403, "no")
}
});
} else {
throw new HttpError(403, "no")
}
//
try {
jwt.verify(provided_token, process.env.JWT_SECRET || "secretjwtsecret");
return true
} catch (error) {
return false
}
}
export default authchecker

View File

@ -1,4 +1,4 @@
import { JsonController, Param, Body, Get, Post, Put, Delete, NotFoundError, OnUndefined, NotAcceptableError } from 'routing-controllers';
import { JsonController, Param, Body, Get, Post, Put, Delete, NotFoundError, OnUndefined, NotAcceptableError, Authorized } from 'routing-controllers';
import { getConnectionManager, Repository } from 'typeorm';
import { EntityFromBody } from 'typeorm-routing-controllers-extensions';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
@ -22,6 +22,7 @@ export class TrackNotFoundError extends NotFoundError {
}
@JsonController('/tracks')
@Authorized("TRACKS:read")
export class TrackController {
private trackRepository: Repository<Track>;
@ -34,7 +35,7 @@ export class TrackController {
@Get()
@ResponseSchema(Track, { isArray: true })
@OpenAPI({description: "Lists all tracks."})
@OpenAPI({ description: "Lists all tracks." })
getAll() {
return this.trackRepository.find();
}
@ -42,14 +43,14 @@ export class TrackController {
@Get('/:id')
@ResponseSchema(Track)
@OnUndefined(TrackNotFoundError)
@OpenAPI({description: "Returns a track of a specified id (if it exists)"})
@OpenAPI({ description: "Returns a track of a specified id (if it exists)" })
getOne(@Param('id') id: number) {
return this.trackRepository.findOne({ id: id });
}
@Post()
@ResponseSchema(Track)
@OpenAPI({description: "Create a new track object (id will be generated automagicly)."})
@OpenAPI({ description: "Create a new track object (id will be generated automagicly)." })
post(
@Body({ validate: true })
track: CreateTrack
@ -59,15 +60,15 @@ export class TrackController {
@Put('/:id')
@ResponseSchema(Track)
@OpenAPI({description: "Update a track object (id can't be changed)."})
@OpenAPI({ description: "Update a track object (id can't be changed)." })
async put(@Param('id') id: number, @EntityFromBody() track: Track) {
let oldTrack = await this.trackRepository.findOne({ id: id });
if (!oldTrack) {
throw new TrackNotFoundError();
throw new TrackNotFoundError();
}
if(oldTrack.id != track.id){
if (oldTrack.id != track.id) {
throw new NotAcceptableError("The id's don't match!");
}
@ -77,7 +78,7 @@ export class TrackController {
@Delete('/:id')
@ResponseSchema(Track)
@OpenAPI({description: "Delete a specified track (if it exists)."})
@OpenAPI({ description: "Delete a specified track (if it exists)." })
async remove(@Param('id') id: number) {
let track = await this.trackRepository.findOne({ id: id });

View File

@ -0,0 +1,20 @@
import {
Middleware,
ExpressErrorMiddlewareInterface
} from "routing-controllers";
@Middleware({ type: "after" })
export class ErrorHandler implements ExpressErrorMiddlewareInterface {
public error(
error: any,
request: any,
response: any,
next: (err: any) => any
) {
if (response.headersSent) {
return;
}
response.json(error);
}
}