Skip to content

Commit 6b866a9

Browse files
auth tokens requirement added
1 parent 0921bd5 commit 6b866a9

File tree

15 files changed

+499
-187
lines changed

15 files changed

+499
-187
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ private getGoogleMaps(): Promise<any> {
9292
* [Google Maps Javascript API](https://developers.google.com/maps/documentation/javascript/tutorial) map-modal added to new-offer page. Clicking on 'SELECT LOCATION' will open Google Maps at a fixed location. Address of place extracted from Google Maps data and stored in Places database.
9393
* [Capacitor Geolocation API](https://capacitor.ionicframework.com/docs/apis/geolocation) used to provide current location.
9494
* [Capacitor Camera API](https://capacitor.ionicframework.com/docs/apis/camera) used to provide camera functionality.
95+
* [Firebase Auth API](https://firebase.google.com/docs/reference/rest/auth) used to control access to app.
96+
* [Cordova Local Storage](https://cordova.apache.org/docs/en/latest/cordova/storage/storage.html#localstorage) to save user user authentication token so a refresh etc. does not lose a user's settings.
97+
* Auth tokens on the backend.
9598

9699
## Status & To-do list
97100

functions/index.js

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ exports.storeImage = functions.https.onRequest((req, res) => {
1717
if (req.method !== 'POST') {
1818
return res.status(500).json({ message: 'Not allowed.' });
1919
}
20+
21+
if (!req.headers.authorizaton || !req.headers.authorizaton.startsWith('Bear ')) {
22+
return res.status(401).json({ error: 'Unauthorized' });
23+
}
24+
25+
let idToken;
26+
idToken = req.headers.authorization.split('Bearer ')[1];
27+
2028
const busboy = new Busboy({ headers: req.headers });
2129
let uploadData;
2230
let oldImagePath;
@@ -38,20 +46,24 @@ exports.storeImage = functions.https.onRequest((req, res) => {
3846
imagePath = oldImagePath;
3947
}
4048

41-
console.log(uploadData.type);
42-
return storage
43-
.bucket('ionic-angular-project-a9d42.appspot.com')
44-
.upload(uploadData.filePath, {
45-
uploadType: 'media',
46-
destination: imagePath,
47-
metadata: {
48-
metadata: {
49-
contentType: uploadData.type,
50-
firebaseStorageDownloadTokens: id
51-
}
52-
}
49+
return fbAdmin
50+
.auth()
51+
.verifyIdToken(idToken)
52+
.then(decodedToken => {
53+
console.log(uploadData.type);
54+
return storage
55+
.bucket('ionic-angular-project-a9d42.appspot.com')
56+
.upload(uploadData.filePath, {
57+
uploadType: 'media',
58+
destination: imagePath,
59+
metadata: {
60+
metadata: {
61+
contentType: uploadData.type,
62+
firebaseStorageDownloadTokens: id
63+
}
64+
}
65+
})
5366
})
54-
5567
.then(() => {
5668
return res.status(201).json({
5769
imageUrl:

src/app/app.component.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
1-
import { Component } from '@angular/core';
1+
import { Component, OnInit, OnDestroy } from '@angular/core';
22
import { Platform } from '@ionic/angular';
33
import { Plugins, Capacitor } from '@capacitor/core';
44

55
import { Router } from '@angular/router';
66

77
import { AuthService } from './auth/auth.service';
8+
import { Subscription } from 'rxjs';
89

910

1011
@Component({
1112
selector: 'app-root',
1213
templateUrl: 'app.component.html',
1314
styleUrls: ['app.component.scss']
1415
})
15-
export class AppComponent {
16+
export class AppComponent implements OnInit, OnDestroy {
17+
private authSub: Subscription;
18+
private previousAuthState = false;
19+
1620
constructor(
1721
private platform: Platform,
1822
private authService: AuthService,
@@ -29,9 +33,23 @@ export class AppComponent {
2933
});
3034
}
3135

36+
ngOnInit() {
37+
this.authSub = this.authService.userIsAuthenticated.subscribe(isAuth => {
38+
if (!isAuth && this.previousAuthState !== isAuth) {
39+
this.router.navigateByUrl('/auth');
40+
}
41+
this.previousAuthState = isAuth;
42+
});
43+
}
44+
3245
onLogout() {
3346
this.authService.logout();
34-
this.router.navigateByUrl('/auth');
47+
}
48+
49+
ngOnDestroy() {
50+
if (this.authSub) {
51+
this.authSub.unsubscribe();
52+
}
3553
}
3654

3755
}

src/app/auth/auth.guard.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { Injectable } from '@angular/core';
22
import { CanLoad, Route, UrlSegment, Router } from '@angular/router';
3-
import { Observable } from 'rxjs';
3+
import { Observable, of } from 'rxjs';
44

55
import { AuthService } from './auth.service';
6+
import { take, tap, switchMap } from 'rxjs/operators';
67

78
@Injectable({
89
providedIn: 'root'
@@ -14,9 +15,20 @@ export class AuthGuard implements CanLoad {
1415
route: Route,
1516
segments: UrlSegment[]
1617
): Observable<boolean> | Promise<boolean> | boolean {
17-
if (!this.authService.userIsAuthenticated) {
18-
this.router.navigateByUrl('/auth');
19-
}
20-
return this.authService.userIsAuthenticated;
18+
return this.authService.userIsAuthenticated.pipe(
19+
take(1),
20+
switchMap(isAuthenticated => {
21+
if (!isAuthenticated) {
22+
return this.authService.autoLogin();
23+
} else {
24+
return of(isAuthenticated);
25+
}
26+
}),
27+
tap(isAuthenticated => {
28+
if (!isAuthenticated) {
29+
this.router.navigateByUrl('/auth');
30+
}
31+
})
32+
);
2133
}
2234
}

src/app/auth/auth.page.html

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,9 @@
7070
<ion-button
7171
type="submit"
7272
color="primary"
73-
(click)="onLogin()"
7473
expand="block"
7574
[disabled]="!f.valid">
76-
Login
75+
{{ isLogin ? 'Login' : 'Signup' }}
7776
</ion-button>
7877
</ion-col>
7978
</ion-row>

src/app/auth/auth.page.ts

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
import { Observable } from 'rxjs';
12
import { Component, OnInit } from '@angular/core';
23
import { Router } from '@angular/router';
34
import { NgForm } from '@angular/forms';
4-
import { LoadingController } from '@ionic/angular';
5+
import { LoadingController, AlertController } from '@ionic/angular';
6+
7+
import { AuthService, AuthResponseData } from './auth.service';
8+
59

6-
import { AuthService } from './auth.service';
710
@Component({
811
selector: 'app-auth',
912
templateUrl: './auth.page.html',
@@ -16,24 +19,45 @@ export class AuthPage implements OnInit {
1619
constructor(
1720
private authService: AuthService,
1821
private router: Router,
19-
private loadingCtrl: LoadingController
22+
private loadingCtrl: LoadingController,
23+
private alertCtrl: AlertController
2024
) { }
2125

2226
ngOnInit() {
2327
}
2428

25-
onLogin() {
29+
authenticate(email: string, password: string) {
2630
this.isLoading = true;
27-
this.authService.login();
2831
this.loadingCtrl
29-
.create({keyboardClose: true, message: 'Logging in...'})
32+
.create({ keyboardClose: true, message: 'Logging in...' })
3033
.then(loadingEl => {
3134
loadingEl.present(); // mask over screen while loading
32-
setTimeout(() => {
33-
this.isLoading = false;
34-
loadingEl.dismiss();
35-
this.router.navigateByUrl('/places/tabs/discover');
36-
}, 1500);
35+
let authObs: Observable<AuthResponseData>;
36+
if (this.isLogin) {
37+
authObs = this.authService.login(email, password);
38+
} else {
39+
authObs = this.authService.signup(email, password);
40+
}
41+
authObs.subscribe(
42+
resData => {
43+
this.isLoading = false;
44+
loadingEl.dismiss();
45+
this.router.navigateByUrl('/places/tabs/discover');
46+
},
47+
errRes => {
48+
loadingEl.dismiss();
49+
const code = errRes.error.error.message;
50+
let message = 'Could not sign you up, try again';
51+
if (code === 'EMAIL_EXISTS') {
52+
message = 'This email address already exists';
53+
} else if (code === 'EMAIL_NOT_FOUND') {
54+
message = 'email address could not be found';
55+
} else if (code === 'INVALID_PASSWORD') {
56+
message = 'This password is not correct';
57+
}
58+
this.showAlert(message);
59+
}
60+
);
3761
});
3862
}
3963

@@ -48,13 +72,18 @@ export class AuthPage implements OnInit {
4872
}
4973
const email = form.value.email;
5074
const password = form.value.password;
51-
console.log(email, password);
5275

53-
if (this.isLogin) {
54-
// send request to login server
55-
} else {
56-
// send request to signup server
57-
}
76+
this.authenticate(email, password);
77+
form.reset();
5878
}
5979

80+
private showAlert(message: string) {
81+
this.alertCtrl
82+
.create({
83+
header: 'Authentication failed',
84+
message,
85+
buttons: ['OK']
86+
})
87+
.then(alertEl => alertEl.present());
88+
}
6089
}

0 commit comments

Comments
 (0)