Reputation: 17
I have a problem with registering a user on my app. In practice, from the Me tab button the user can access his Profile (if he has logged in, otherwise he is redirected to the Login page). enter image description here
The problem is that, after registering, the user can access the Profile page without having verified the email. I can't figure out how to use the emailVerified pipe https://github.com/angular/angularfire/blob/master/docs/auth/router-guards.md . Can anyone tell me how to implement this operation?
Tabs.routing.module:
const redirectUnauthorizedToLogin = () => redirectUnauthorizedTo(['tabs/login']);
const routes: Routes = [
{
path: 'tabs',
component: TabsPage,
children: [
{
path: 'home',
loadChildren: () => import('../home/home.module').then(m => m.HomePageModule)
},
{
path: 'search',
loadChildren: () => import('../search/search.module').then(m => m.SearchPageModule)
},
{
path: 'profile',
loadChildren: () => import('../profile/profile.module').then(m => m.ProfilePageModule),...canActivate(redirectUnauthorizedToLogin),
},
{
path: 'login',
loadChildren: () => import('../login/login.module').then(m => m.LoginPageModule)
},
{
path: 'registration',
loadChildren: () => import('../registration/registration.module').then(m => m.RegistrationPageModule)
},
{
path: '',
redirectTo: '/tabs/home',
pathMatch: 'full'
}
]
},
{
path: '',
redirectTo: '/tabs/home',
pathMatch: 'full'
}
];
Authentication-service:
import { Injectable, NgZone } from '@angular/core';
import { auth } from 'firebase/app';
import { User } from "./user";
import { Router } from "@angular/router";
import { AngularFireAuth } from "@angular/fire/auth";
import { AngularFirestore, AngularFirestoreDocument } from '@angular/fire/firestore';
@Injectable({
providedIn: 'root'
})
export class AuthenticationService {
userData: any;
constructor(
public afStore: AngularFirestore,
public ngFireAuth: AngularFireAuth,
public router: Router,
public ngZone: NgZone
) {
this.ngFireAuth.authState.subscribe(user => {
if (user) {
this.userData = user;
localStorage.setItem('user', JSON.stringify(this.userData));
JSON.parse(localStorage.getItem('user'));
} else {
localStorage.setItem('user', null);
JSON.parse(localStorage.getItem('user'));
}
})
}
// Login in with email/password
SignIn(email, password) {
return this.ngFireAuth.signInWithEmailAndPassword(email, password)
}
// Register user with email/password
RegisterUser(email, password) {
return this.ngFireAuth.createUserWithEmailAndPassword(email, password)
}
// Email verification when new user register
SendVerificationMail() {
return this.ngFireAuth.currentUser.then(u => u.sendEmailVerification())
.then(() => {
this.router.navigate(['tabs/verify-email']);
})
}
// Recover password
PasswordRecover(passwordResetEmail) {
return this.ngFireAuth.sendPasswordResetEmail(passwordResetEmail)
.then(() => {
window.alert('Password reset email has been sent, please check your inbox.');
}).catch((error) => {
window.alert(error)
})
}
// Returns true when user is looged in
get isLoggedIn(): boolean {
const user = JSON.parse(localStorage.getItem('user'));
return (user !== null && user.emailVerified !== false) ? true : false;
}
// Returns true when user's email is verified
get isEmailVerified(): boolean {
const user = JSON.parse(localStorage.getItem('user'));
return (user.emailVerified !== false) ? true : false;
}
// Sign in with Gmail
GoogleAuth() {
return this.AuthLogin(new auth.GoogleAuthProvider());
}
// Auth providers
AuthLogin(provider) {
return this.ngFireAuth.signInWithPopup(provider)
.then((result) => {
this.ngZone.run(() => {
this.router.navigate(['tabs/home']);
})
this.SetUserData(result.user);
}).catch((error) => {
window.alert(error)
})
}
// Store user in localStorage
SetUserData(user) {
const userRef: AngularFirestoreDocument<any> = this.afStore.doc(`users/${user.uid}`);
const userData: User = {
uid: user.uid,
email: user.email,
displayName: user.displayName,
photoURL: user.photoURL,
emailVerified: user.emailVerified
}
return userRef.set(userData, {
merge: true
})
}
// Sign-out
SignOut() {
return this.ngFireAuth.signOut().then(() => {
localStorage.removeItem('user');
this.router.navigate(['tabs/login']);
})
}
}
Upvotes: 0
Views: 1280
Reputation: 1568
If you need to redirect to different paths if the user is unauthorized or has email unverified, you can use an inner map.
/** Redirect users to login screen or email confirmation screen */
const redirectToEmailConfirm: AuthPipeGenerator = (
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot
) =>
switchMap((user) => {
return of(user).pipe(
redirectUnauthorizedTo(`/login?redirectTo=${state.url}`),
map((result) => {
if (result === true) {
// User is authorized
if (user.emailVerified) {
return true;
} else {
return ['/verify-email'];
}
} else {
return result;
}
})
);
});
Upvotes: 3
Reputation: 153
I just had the same issue and managed to solve it like this. In your Tabs.routing.module document you import redirectUnauthorizedTo from AngularFire which by default checks if the user is logged in, not if the suer is logged in AND verified.
Instead you can write your own redirectUnauthorizedTo function called redirectUnverifiedTo like this.
First, make sure to import emailVerified and not redirectUnauthorizedTo.
import { AngularFireAuthGuard, emailVerified } from '@angular/fire/auth-guard';
Then define redirectUnverifiedTo.
const redirectUnverifiedTo = (redirect: any[]) => pipe(emailVerified, map(emailVerified => emailVerified || redirect));
const redirectUnauthorizedToLogin = () => redirectUnverifiedTo(['tabs/login']);
Finally you can use redirectUnauthorizedToLogin like normal!
Upvotes: 1