Skip to content

Commit 83d052b

Browse files
author
hirsch88
committed
✨ Add simple basic auth authentication
1 parent 9083772 commit 83d052b

10 files changed

+70
-78
lines changed

src/api/controllers/UserController.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ export class UserController {
1212

1313
constructor(
1414
private userService: UserService
15-
) { }
15+
) {
16+
console.log('UserControllerUserControllerUserController');
17+
}
1618

1719
@Get()
1820
public find( @CurrentUser() user?: User): Promise<User[]> {

src/api/models/User.ts

+10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Exclude } from 'class-transformer';
12
import { IsNotEmpty } from 'class-validator';
23
import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
34

@@ -21,6 +22,15 @@ export class User {
2122
@Column()
2223
public email: string;
2324

25+
@IsNotEmpty()
26+
@Column()
27+
@Exclude()
28+
public password: string;
29+
30+
@IsNotEmpty()
31+
@Column()
32+
public username: string;
33+
2434
@OneToMany(type => Pet, pet => pet.user)
2535
public pets: Pet[];
2636

src/api/swagger.json

+12-14
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,8 @@
1515
],
1616
"schemes": [],
1717
"securityDefinitions": {
18-
"JWT": {
19-
"type": "apiKey",
20-
"in": "header",
21-
"name": "Authorization"
18+
"basicAuth": {
19+
"type": "basic"
2220
}
2321
},
2422
"tags": [
@@ -58,7 +56,7 @@
5856
"operationId": "FindAllUsers",
5957
"security": [
6058
{
61-
"JWT": []
59+
"basicAuth": []
6260
}
6361
],
6462
"responses": {
@@ -93,7 +91,7 @@
9391
"operationId": "CreateUser",
9492
"security": [
9593
{
96-
"JWT": []
94+
"basicAuth": []
9795
}
9896
],
9997
"parameters": [
@@ -138,7 +136,7 @@
138136
"operationId": "FindUser",
139137
"security": [
140138
{
141-
"JWT": []
139+
"basicAuth": []
142140
}
143141
],
144142
"parameters": [
@@ -180,7 +178,7 @@
180178
"operationId": "UpdateUser",
181179
"security": [
182180
{
183-
"JWT": []
181+
"basicAuth": []
184182
}
185183
],
186184
"parameters": [
@@ -231,7 +229,7 @@
231229
"operationId": "DeleteUser",
232230
"security": [
233231
{
234-
"JWT": []
232+
"basicAuth": []
235233
}
236234
],
237235
"parameters": [
@@ -272,7 +270,7 @@
272270
"operationId": "FindAllPets",
273271
"security": [
274272
{
275-
"JWT": []
273+
"basicAuth": []
276274
}
277275
],
278276
"responses": {
@@ -307,7 +305,7 @@
307305
"operationId": "CreatePet",
308306
"security": [
309307
{
310-
"JWT": []
308+
"basicAuth": []
311309
}
312310
],
313311
"parameters": [
@@ -352,7 +350,7 @@
352350
"operationId": "FindPet",
353351
"security": [
354352
{
355-
"JWT": []
353+
"basicAuth": []
356354
}
357355
],
358356
"parameters": [
@@ -394,7 +392,7 @@
394392
"operationId": "UpdatePet",
395393
"security": [
396394
{
397-
"JWT": []
395+
"basicAuth": []
398396
}
399397
],
400398
"parameters": [
@@ -445,7 +443,7 @@
445443
"operationId": "DeletePet",
446444
"security": [
447445
{
448-
"JWT": []
446+
"basicAuth": []
449447
}
450448
],
451449
"parameters": [

src/auth/AuthService.ts

+22-32
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,46 @@
11
import * as express from 'express';
2-
import * as request from 'request';
32
import { Service } from 'typedi';
3+
import { OrmRepository } from 'typeorm-typedi-extensions';
44

5+
import { User } from '../api/models/User';
6+
import { UserRepository } from '../api/repositories/UserRepository';
57
import { Logger, LoggerInterface } from '../decorators/Logger';
6-
import { env } from '../env';
7-
import { TokenInfoInterface } from './TokenInfoInterface';
88

99
@Service()
1010
export class AuthService {
1111

12-
private httpRequest: typeof request;
13-
1412
constructor(
15-
@Logger(__filename) private log: LoggerInterface
16-
) {
17-
this.httpRequest = request;
18-
}
13+
@Logger(__filename) private log: LoggerInterface,
14+
@OrmRepository() private userRepository: UserRepository
15+
) { }
1916

20-
public parseTokenFromRequest(req: express.Request): string | undefined {
17+
public parseBasicAuthFromRequest(req: express.Request): { username: string, password: string } {
2118
const authorization = req.header('authorization');
2219

2320
// Retrieve the token form the Authorization header
24-
if (authorization && authorization.split(' ')[0] === 'Bearer') {
21+
if (authorization && authorization.split(' ')[0] === 'Basic') {
2522
this.log.info('Token provided by the client');
26-
return authorization.split(' ')[1];
23+
const decodedToken = Buffer.from(authorization.split(' ')[1], 'base64').toString('ascii');
24+
const username = decodedToken.split(':')[0];
25+
const password = decodedToken.split(':')[1];
26+
return { username, password };
2727
}
2828

2929
this.log.info('No Token provided by the client');
3030
return undefined;
3131
}
3232

33-
public getTokenInfo(token: string): Promise<TokenInfoInterface> {
34-
return new Promise((resolve, reject) => {
35-
this.httpRequest({
36-
method: 'POST',
37-
url: env.auth.route,
38-
form: {
39-
id_token: token,
40-
},
41-
}, (error: any, response: request.RequestResponse, body: any) => {
42-
// Verify if the requests was successful and append user
43-
// information to our extended express request object
44-
if (!error) {
45-
if (response.statusCode === 200) {
46-
const tokeninfo = JSON.parse(body);
47-
return resolve(tokeninfo);
48-
}
49-
return reject(body);
50-
}
51-
return reject(error);
52-
});
33+
public async validateUser(username: string, password: string): Promise<User> {
34+
const user = await this.userRepository.findOne({
35+
where: {
36+
username,
37+
password,
38+
},
5339
});
40+
if (user) {
41+
return user;
42+
}
43+
throw new Error('Invalid credentials');
5444
}
5545

5646
}

src/auth/TokenInfoInterface.ts

-3
This file was deleted.

src/auth/authorizationChecker.ts

+5-7
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,16 @@ export function authorizationChecker(connection: Connection): (action: Action, r
1515
// you can use them to provide granular access check
1616
// checker must return either boolean (true or false)
1717
// either promise that resolves a boolean value
18-
// demo code:
19-
const token = authService.parseTokenFromRequest(action.request);
18+
const credentials = authService.parseBasicAuthFromRequest(action.request);
2019

21-
if (token === undefined) {
22-
log.warn('No token given');
20+
if (credentials === undefined) {
21+
log.warn('No credentials given');
2322
return false;
2423
}
2524

26-
// Request user info at auth0 with the provided token
2725
try {
28-
action.request.tokeninfo = await authService.getTokenInfo(token);
29-
log.info('Successfully checked token');
26+
action.request.user = await authService.validateUser(credentials.username, credentials.password);
27+
log.info('Successfully checked credentials');
3028
return true;
3129
} catch (e) {
3230
log.warn(e);

src/auth/currentUserChecker.ts

+1-21
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,9 @@ import { Action } from 'routing-controllers';
22
import { Connection } from 'typeorm';
33

44
import { User } from '../api/models/User';
5-
import { Logger } from '../lib/logger';
6-
import { TokenInfoInterface } from './TokenInfoInterface';
75

86
export function currentUserChecker(connection: Connection): (action: Action) => Promise<User | undefined> {
9-
const log = new Logger(__filename);
10-
117
return async function innerCurrentUserChecker(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: TokenInfoInterface = action.request.tokeninfo;
16-
const em = connection.createEntityManager();
17-
const user = await em.findOne<User>(User, {
18-
where: {
19-
email: tokeninfo.user_id.replace('auth0|', ''),
20-
},
21-
});
22-
if (user) {
23-
log.info('Current user is ', user.toString());
24-
} else {
25-
log.info('Current user is undefined');
26-
}
27-
28-
return user;
8+
return action.request.user;
299
};
3010
}

src/database/factories/UserFactory.ts

+3
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@ define(User, (faker: typeof Faker, settings: { role: string }) => {
88
const firstName = faker.name.firstName(gender);
99
const lastName = faker.name.lastName(gender);
1010
const email = faker.internet.email(firstName, lastName);
11+
const username = faker.internet.userName(firstName, lastName);
1112

1213
const user = new User();
1314
user.firstName = firstName;
1415
user.lastName = lastName;
1516
user.email = email;
17+
user.username = username;
18+
user.password = '1234';
1619
return user;
1720
});

src/database/migrations/1511105183653-CreateUserTable.ts

+12
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,18 @@ export class CreateUserTable1511105183653 implements MigrationInterface {
3030
length: '255',
3131
isPrimary: false,
3232
isNullable: false,
33+
}, {
34+
name: 'username',
35+
type: 'varchar',
36+
length: '255',
37+
isPrimary: false,
38+
isNullable: false,
39+
} , {
40+
name: 'password',
41+
type: 'varchar',
42+
length: '255',
43+
isPrimary: false,
44+
isNullable: false,
3345
},
3446
],
3547
});

src/database/seeds/CreateBruce.ts

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ export class CreateBruce implements Seed {
3232
user.firstName = 'Bruce';
3333
user.lastName = 'Wayne';
3434
user.email = 'bruce.wayne@wayne-enterprises.com';
35+
user.username = 'bruce';
36+
user.password = '1234';
3537
return await em.save(user);
3638
}
3739

0 commit comments

Comments
 (0)