Skip to content

Commit 2f3e2cc

Browse files
author
hirsch88
committed
Add auth
1 parent 466a140 commit 2f3e2cc

12 files changed

+196
-8
lines changed

Diff for: .env.example

+5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ LOG_LEVEL="debug"
1212
LOG_JSON=false
1313
LOG_OUTPUT="dev"
1414

15+
#
16+
# AUTHORIZATION
17+
#
18+
AUTH_ROUTE="http://localhost:3333/tokeninfo"
19+
1520
#
1621
# DATABASE
1722
#

Diff for: package.json

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"scripts": {
1010
"start": "node dist/app.js",
1111
"test": "nps test",
12+
"build": "nps build",
1213
"ts-node": "./node_modules/.bin/ts-node",
1314
"ts-node:fast": "./node_modules/.bin/ts-node -F",
1415
"console": "npm run ts-node:fast -- ./src/console/lib/console.ts",
@@ -50,13 +51,15 @@
5051
"@types/lodash": "^4.14.80",
5152
"@types/morgan": "^1.7.35",
5253
"@types/reflect-metadata": "0.0.5",
54+
"@types/request": "^2.0.8",
5355
"@types/serve-favicon": "^2.2.29",
5456
"@types/uuid": "^3.4.3",
5557
"@types/winston": "^2.3.7",
5658
"ascii-art": "^1.4.2",
5759
"body-parser": "^1.18.2",
5860
"class-validator": "^0.7.3",
5961
"compression": "^1.7.1",
62+
"copyfiles": "^1.2.0",
6063
"cors": "^2.8.4",
6164
"dotenv": "^4.0.0",
6265
"express": "^4.16.2",
@@ -71,6 +74,7 @@
7174
"nodemon": "^1.12.1",
7275
"path": "^0.12.7",
7376
"reflect-metadata": "^0.1.10",
77+
"request": "^2.83.0",
7478
"routing-controllers": "^0.7.6",
7579
"serve-favicon": "^2.4.5",
7680
"swagger-ui-express": "^2.0.10",

Diff for: src/api/controllers/UserController.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
1-
import { JsonController, Get, Post, Put, Param, Delete, Body, OnUndefined } from 'routing-controllers';
1+
import { JsonController, Get, Post, Put, Param, Delete, Body, OnUndefined, Authorized, CurrentUser } from 'routing-controllers';
22
import { Inject } from 'typedi';
33
import { UserService } from '../services/UserService';
44
import { User } from '../models/User';
55
import { UserNotFoundError } from '../errors/UserNotFoundError';
66

77

8+
@Authorized()
89
@JsonController('/users')
910
export class UserController {
1011

1112
@Inject()
1213
private userService: UserService;
1314

1415
@Get()
15-
public find(): Promise<User[]> {
16+
public find( @CurrentUser() user?: User): Promise<User[]> {
1617
return this.userService.find();
1718
}
1819

Diff for: src/api/models/User.ts

+4
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,8 @@ export class User extends BaseEntity {
1616
@Column({ name: 'last_name' })
1717
public lastName: string;
1818

19+
@IsNotEmpty()
20+
@Column()
21+
public email: string;
22+
1923
}

Diff for: src/auth/AuthService.ts

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import * as request from 'request';
2+
import { Service } from 'typedi';
3+
import { env } from '../core/env';
4+
import { ITokenInfo } from './ITokenInfo';
5+
6+
7+
@Service()
8+
export class AuthService {
9+
10+
public parseTokenFromRequest(req: myExpress.Request): string | null {
11+
const authorization = req.header('authorization');
12+
13+
// Retrieve the token form the Authorization header
14+
if (authorization && authorization.split(' ')[0] === 'Bearer') {
15+
return authorization.split(' ')[1];
16+
}
17+
18+
// No token was provided by the client
19+
return null;
20+
}
21+
22+
public getTokenInfo(token: string): Promise<ITokenInfo> {
23+
return new Promise((resolve, reject) => {
24+
request({
25+
method: 'POST',
26+
url: env.auth.route,
27+
form: {
28+
id_token: token
29+
}
30+
}, (error: any, response: request.RequestResponse, body: any) => {
31+
// Verify if the requests was successful and append user
32+
// information to our extended express request object
33+
if (!error) {
34+
if (response.statusCode === 200) {
35+
const tokeninfo = JSON.parse(body);
36+
return resolve(tokeninfo);
37+
}
38+
return reject(body);
39+
}
40+
return reject(error);
41+
});
42+
});
43+
}
44+
45+
}

Diff for: src/auth/ITokenInfo.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export interface ITokenInfo {
2+
user_id: string;
3+
}

Diff for: src/auth/authorizationChecker.ts

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { Action } from 'routing-controllers';
2+
import { Container } from 'typedi';
3+
import { AuthService } from './AuthService';
4+
import { Log } from '../core/Log';
5+
6+
const log = new Log(__filename);
7+
const authService = Container.get(AuthService);
8+
9+
10+
export async function authorizationChecker(action: Action, roles: string[]): Promise<boolean> {
11+
// here you can use request/response objects from action
12+
// also if decorator defines roles it needs to access the action
13+
// you can use them to provide granular access check
14+
// checker must return either boolean (true or false)
15+
// either promise that resolves a boolean value
16+
// demo code:
17+
const token = authService.parseTokenFromRequest(action.request);
18+
19+
if (token === null) {
20+
log.warn('No token given');
21+
return false; // res.failed(403, 'You are not allowed to request this resource!');
22+
}
23+
24+
// Request user info at auth0 with the provided token
25+
try {
26+
action.request.tokeninfo = await authService.getTokenInfo(token);
27+
log.info('Successfully checked token');
28+
return true;
29+
} catch (e) {
30+
log.warn(e);
31+
return false;
32+
}
33+
}

Diff for: src/auth/currentUserChecker.ts

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { Action } from 'routing-controllers';
2+
import { User } from '../api/models/User';
3+
import { Log } from '../core/Log';
4+
import { ITokenInfo } from './ITokenInfo';
5+
// import { UserRepository } from '../api/repositories/UserRepository';
6+
// import { getConnection } from 'typeorm';
7+
8+
const log = new Log(__filename);
9+
10+
11+
export async function currentUserChecker(action: Action): Promise<User | undefined> {
12+
// here you can use request/response objects from action
13+
// you need to provide a user object that will be injected in controller actions
14+
// demo code:
15+
const tokeninfo: ITokenInfo = action.request.tokeninfo;
16+
log.info('todo user checker', tokeninfo);
17+
18+
// const connection = getConnection();
19+
20+
// const userRepository = connection.getRepository<User>(UserRepository);
21+
// console.log(connection);
22+
// const user = await userRepository.
23+
// findOne({
24+
// where: {
25+
// email: tokeninfo.user_id
26+
// }
27+
// });
28+
// console.log(user);
29+
30+
return Promise.resolve(new User());
31+
}
32+

Diff for: src/core/env.ts

+3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ export const env = {
1818
json: toBool(getOsEnv('LOG_JSON')),
1919
output: getOsEnv('LOG_OUTPUT')
2020
},
21+
auth: {
22+
route: getOsEnv('AUTH_ROUTE')
23+
},
2124
db: {
2225
type: getOsEnv('DB_TYPE'),
2326
host: getOsEnv('DB_HOST'),

Diff for: src/loaders/expressLoader.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { useContainer as ormUseContainer } from 'typeorm';
44
import { useContainer as routingUseContainer, createExpressServer } from 'routing-controllers';
55
import { MicroframeworkSettings, MicroframeworkLoader } from 'microframework';
66
import { env } from '../core/env';
7+
import { authorizationChecker } from '../auth/authorizationChecker';
8+
import { currentUserChecker } from '../auth/currentUserChecker';
79

810

911
export const expressLoader: MicroframeworkLoader = (settings: MicroframeworkSettings | undefined) => {
@@ -27,8 +29,13 @@ export const expressLoader: MicroframeworkLoader = (settings: MicroframeworkSett
2729
*/
2830
controllers: [path.join(__dirname, '..', 'api/controllers/*{.js,.ts}')],
2931
middlewares: [path.join(__dirname, '..', 'api/middlewares/*{.js,.ts}')],
30-
interceptors: [path.join(__dirname, '..', 'api/interceptors/*{.js,.ts}')]
32+
interceptors: [path.join(__dirname, '..', 'api/interceptors/*{.js,.ts}')],
3133

34+
/**
35+
* Authorization features
36+
*/
37+
authorizationChecker,
38+
currentUserChecker
3239
});
3340

3441
// Run application to listen on given port

Diff for: src/loaders/typeormLoader.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
import * as path from 'path';
12
import { createConnection } from 'typeorm';
23
import { MicroframeworkSettings, MicroframeworkLoader } from 'microframework';
34
import { env } from '../core/env';
4-
import { User } from '../api/models/User';
55

66

77
export const typeormLoader: MicroframeworkLoader = async (settings: MicroframeworkSettings | undefined) => {
@@ -16,7 +16,7 @@ export const typeormLoader: MicroframeworkLoader = async (settings: Microframewo
1616
synchronize: env.db.synchronize,
1717
logging: env.db.logging,
1818
entities: [
19-
User
19+
path.join(__dirname, '..', 'api/models/*{.js,.ts}')
2020
]
2121
});
2222

Diff for: yarn.lock

+54-3
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@
4343
"@types/express-serve-static-core" "*"
4444
"@types/serve-static" "*"
4545

46+
"@types/form-data@*":
47+
version "2.2.1"
48+
resolved "https://registry.yarnpkg.com/@types/form-data/-/form-data-2.2.1.tgz#ee2b3b8eaa11c0938289953606b745b738c54b1e"
49+
dependencies:
50+
"@types/node" "*"
51+
4652
"@types/helmet@^0.0.37":
4753
version "0.0.37"
4854
resolved "https://registry.yarnpkg.com/@types/helmet/-/helmet-0.0.37.tgz#6b150f30219c0d6563e8e0a3fbcad8dd90fa4f68"
@@ -75,6 +81,13 @@
7581
version "0.0.5"
7682
resolved "https://registry.yarnpkg.com/@types/reflect-metadata/-/reflect-metadata-0.0.5.tgz#9c042bfa9803d577aad4f57dfbca4b7cae4286fe"
7783

84+
"@types/request@^2.0.8":
85+
version "2.0.8"
86+
resolved "https://registry.yarnpkg.com/@types/request/-/request-2.0.8.tgz#424d3de255868107ed4dd6695c65c5f1766aba80"
87+
dependencies:
88+
"@types/form-data" "*"
89+
"@types/node" "*"
90+
7891
"@types/serve-favicon@^2.2.29":
7992
version "2.2.30"
8093
resolved "https://registry.yarnpkg.com/@types/serve-favicon/-/serve-favicon-2.2.30.tgz#5bea4ead966a9ad5e0f409141edba0cebf20da73"
@@ -981,6 +994,17 @@ cookie@0.3.1, cookie@^0.3.1:
981994
version "0.3.1"
982995
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
983996

997+
copyfiles@^1.2.0:
998+
version "1.2.0"
999+
resolved "https://registry.yarnpkg.com/copyfiles/-/copyfiles-1.2.0.tgz#a8da3ac41aa2220ae29bd3c58b6984294f2c593c"
1000+
dependencies:
1001+
glob "^7.0.5"
1002+
ltcdr "^2.2.1"
1003+
minimatch "^3.0.3"
1004+
mkdirp "^0.5.1"
1005+
noms "0.0.0"
1006+
through2 "^2.0.1"
1007+
9841008
core-js@^2.4.0, core-js@^2.4.1, core-js@^2.5.0:
9851009
version "2.5.1"
9861010
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.1.tgz#ae6874dc66937789b80754ff5428df66819ca50b"
@@ -2884,6 +2908,10 @@ lru-cache@^4.0.0, lru-cache@^4.0.1:
28842908
pseudomap "^1.0.2"
28852909
yallist "^2.1.2"
28862910

2911+
ltcdr@^2.2.1:
2912+
version "2.2.1"
2913+
resolved "https://registry.yarnpkg.com/ltcdr/-/ltcdr-2.2.1.tgz#5ab87ad1d4c1dab8e8c08bbf037ee0c1902287cf"
2914+
28872915
make-dir@^1.0.0:
28882916
version "1.1.0"
28892917
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.1.0.tgz#19b4369fe48c116f53c2af95ad102c0e39e85d51"
@@ -3134,6 +3162,13 @@ nodemon@^1.12.1:
31343162
undefsafe "0.0.3"
31353163
update-notifier "^2.2.0"
31363164

3165+
noms@0.0.0:
3166+
version "0.0.0"
3167+
resolved "https://registry.yarnpkg.com/noms/-/noms-0.0.0.tgz#da8ebd9f3af9d6760919b27d9cdc8092a7332859"
3168+
dependencies:
3169+
inherits "^2.0.1"
3170+
readable-stream "~1.0.31"
3171+
31373172
nopt@^4.0.1:
31383173
version "4.0.1"
31393174
resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
@@ -3671,7 +3706,7 @@ read-pkg@^2.0.0:
36713706
normalize-package-data "^2.3.2"
36723707
path-type "^2.0.0"
36733708

3674-
readable-stream@2.3.3, readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4:
3709+
readable-stream@2.3.3, readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5:
36753710
version "2.3.3"
36763711
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c"
36773712
dependencies:
@@ -3692,6 +3727,15 @@ readable-stream@^1.0.31:
36923727
isarray "0.0.1"
36933728
string_decoder "~0.10.x"
36943729

3730+
readable-stream@~1.0.31:
3731+
version "1.0.34"
3732+
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c"
3733+
dependencies:
3734+
core-util-is "~1.0.0"
3735+
inherits "~2.0.1"
3736+
isarray "0.0.1"
3737+
string_decoder "~0.10.x"
3738+
36953739
readdirp@^2.0.0:
36963740
version "2.1.0"
36973741
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
@@ -3813,7 +3857,7 @@ request@2.81.0:
38133857
tunnel-agent "^0.6.0"
38143858
uuid "^3.0.0"
38153859

3816-
request@^2.78.0, request@^2.79.0:
3860+
request@^2.78.0, request@^2.79.0, request@^2.83.0:
38173861
version "2.83.0"
38183862
resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356"
38193863
dependencies:
@@ -4360,6 +4404,13 @@ throat@^4.0.0:
43604404
version "4.1.0"
43614405
resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a"
43624406

4407+
through2@^2.0.1:
4408+
version "2.0.3"
4409+
resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be"
4410+
dependencies:
4411+
readable-stream "^2.1.5"
4412+
xtend "~4.0.1"
4413+
43634414
through@2, through@~2.3, through@~2.3.1, through@~2.3.4:
43644415
version "2.3.8"
43654416
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
@@ -4912,7 +4963,7 @@ xmlhttprequest-ssl@~1.5.4:
49124963
version "1.5.4"
49134964
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.4.tgz#04f560915724b389088715cc0ed7813e9677bf57"
49144965

4915-
xtend@^4.0.0, xtend@^4.0.1:
4966+
xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
49164967
version "4.0.1"
49174968
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
49184969

0 commit comments

Comments
 (0)