Skip to content

Commit c4f8183

Browse files
committed
Angular Security course
1 parent eaa7e55 commit c4f8183

11 files changed

+70
-25
lines changed

server/auth.middleware.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {Request, Response, NextFunction} from 'express';
33

44
export function checkIfAuthenticated(req: Request, res: Response, next: NextFunction) {
55

6-
if (req['userId']) {
6+
if (req['user']) {
77
next();
88
}
99
else {

server/database-data.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,19 @@ export const USERS: { [key: number]: DbUser } = {
66
email: 'admin@gmail.com',
77
// ADMIN user (password is Password10) can read all lessons and also can login on behalf of other users
88
passwordDigest: '$argon2i$v=19$m=4096,t=3,p=1$PcKtsL4a6+xuPbMCKPep7A$rrFO2lKZcAVguIMaSGaf3hMrKtb6wUG4zN/wDG+xNts',
9-
roles: [
10-
'READ:LESSONS'
11-
]
9+
roles: {
10+
'READ:LESSONS': true
11+
}
1212
},
1313
2: {
1414
id: 1,
1515
email: 'user@gmail.com',
1616
// normal user (password is Password10), does not have access to login as another user functionality
1717
passwordDigest: '$argon2i$v=19$m=4096,t=3,p=1$PcKtsL4a6+xuPbMCKPep7A$rrFO2lKZcAVguIMaSGaf3hMrKtb6wUG4zN/wDG+xNts',
18-
roles: [
19-
'READ:LESSONS',
20-
'ADMIN'
21-
]
18+
roles: {
19+
'READ:LESSONS': true,
20+
'ADMIN': true
21+
}
2222
}
2323
};
2424

server/db-user.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ export interface DbUser {
44
id:number;
55
email:string;
66
passwordDigest:string,
7-
roles: string[]
7+
roles: Object
88
}

server/get-user.middleware.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ async function handleSessionCookie(jwt:string, req: Request) {
2929

3030
const payload = await decodeJwt(jwt);
3131

32-
req["userId"] = payload.sub;
32+
req["user"] = payload;
3333

3434
}
3535
catch(err) {

server/login-as-user.route.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
2+
3+
4+
import {db} from "./database";
5+
import {createSessionToken} from "./security.utils";
6+
7+
8+
export function loginAsUser(req, res) {
9+
10+
const adminUser = req["user"],
11+
roles = adminUser.userRoles,
12+
userEmail = req.body.email;
13+
14+
if (roles && roles['ADMIN']) {
15+
16+
const newUser = db.findUserByEmail(userEmail);
17+
18+
createSessionToken(newUser)
19+
.then(sessionToken => {
20+
21+
res.cookie("SESSIONID", sessionToken, {httpOnly:true, secure:true});
22+
23+
res.status(200).json({ id: newUser.id, email: newUser.email });
24+
25+
})
26+
.catch(err => {
27+
console.log("Error trying to login as user",err);
28+
res.sendStatus(500);
29+
});
30+
31+
32+
}
33+
else {
34+
res.SendStatus(403);
35+
}
36+
}
37+
38+

server/login.route.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ async function loginAndBuildResponse(credentials:any, user:DbUser, res: Respons
4343
catch(err) {
4444

4545
console.log("Login failed!");
46-
4746
res.sendStatus(403);
47+
4848
}
4949
}
5050

@@ -58,7 +58,7 @@ async function attemptLogin(credentials:any, user:DbUser) {
5858
throw new Error("Password Invalid");
5959
}
6060

61-
return createSessionToken(user.id.toString());
61+
return createSessionToken(user);
6262
}
6363

6464

server/read-all-lessons.route.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ import {db} from "./database";
44

55
export function readAllLessons(req, res) {
66

7-
res.status(200).json({lessons:db.readAllLessons()});
8-
7+
const userRoles = req["user"].roles;
8+
9+
if (userRoles && userRoles['READ:LESSONS']) {
10+
res.status(200).json({lessons:db.readAllLessons()});
11+
}
12+
else {
13+
res.SendStatus(403);
14+
}
915
}

server/security.utils.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const crypto = require('crypto');
77
import * as jwt from 'jsonwebtoken';
88
import * as fs from "fs";
99
import * as argon2 from 'argon2';
10+
import {DbUser} from "./db-user";
1011

1112

1213
export const randomBytes = util.promisify(crypto.randomBytes);
@@ -21,11 +22,12 @@ const RSA_PUBLIC_KEY = fs.readFileSync('./demos/public.key');
2122
const SESSION_DURATION = 1000;
2223

2324

24-
export async function createSessionToken(userId:string) {
25+
export async function createSessionToken(user: DbUser) {
2526
return signJwt({}, RSA_PRIVATE_KEY, {
2627
algorithm: 'RS256',
2728
expiresIn: 240,
28-
subject: userId
29+
subject: user.id,
30+
roles: user.roles
2931
});
3032
}
3133

src/app/admin/admin.component.css

Whitespace-only changes.

src/app/admin/admin.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@
1313
<button class="button button-primary" (click)="loginAsUser()">Login As User</button>
1414
</div>
1515

16+
</form>
1617

17-
</form>

src/app/admin/admin.component.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
1-
import { Component, OnInit } from '@angular/core';
1+
import { Component } from '@angular/core';
22
import {FormBuilder, FormGroup, Validators} from "@angular/forms";
33
import {AuthService} from "../services/auth.service";
44
import {Router} from "@angular/router";
55

66
@Component({
77
selector: 'admin',
88
templateUrl: './admin.component.html',
9-
styleUrls: ['./admin.component.css', '../common/forms.css']
9+
styleUrls: [ '../common/forms.css']
1010
})
1111
export class AdminComponent {
1212

1313
form:FormGroup;
1414

15-
constructor(private fb:FormBuilder, private authService: AuthService, private router: Router) {
15+
constructor(
16+
private fb:FormBuilder,
17+
private authService: AuthService,
18+
private router: Router) {
1619

1720
this.form = this.fb.group({
1821
userEmail: ['user@gmail.com',Validators.required]
@@ -24,19 +27,15 @@ export class AdminComponent {
2427

2528
const val = this.form.value;
2629

27-
if (val.email && val.password) {
28-
30+
if (val.email) {
2931
this.authService.loginAsUser(val.email)
3032
.subscribe(
3133
() => {
3234
console.log("Logged in as user with email " + val.email);
3335
this.router.navigateByUrl('/');
3436
}
3537
);
36-
3738
}
38-
39-
4039
}
4140

4241
}

0 commit comments

Comments
 (0)