I'm trying to restrict access to the Client side Angular app via PassportJS.
Basically i'm trying to route anyone trying to access the app to redirect to the authentication provider to login. But it appears the angular routes override the NodeJS Express routes.
So if i go to '/' it'll just load the angular app and not redirect them. This is the same case for every route that uses the same route as the angular routes.
server.js snippet:
The following code should redirect everyone to log into facebook. but instead it just loads the angular index page.
function checkAuthentication(req,res,next){
if(req.isAuthenticated()){
//if user is looged in, req.isAuthenticated() will return true
console.log("/ " + true);
res.sendFile(path.join(__dirname, 'dist/index.html'));
} else{
console.log("/ " + false);
res.redirect("/api/passport/login/facebook");
}
}
app.get('/*', checkAuthentication ,(req, res) => {
});
Angular index.html snippet:
The index.html page uses the same route as displayed in the express router.
<base href="/">
Let's say i change the index.html base href to use '/app/' like so:
<base href="/app/">
and set up routing in express to redirect logged in users to '/app/' like so:
angular.route example:
app.use("/app", express.static(path.join(__dirname, 'dist')));
function checkAuthentication(req,res,next){
if(req.isAuthenticated()){
//if user is looged in, req.isAuthenticated() will return true
console.log("/app" + true);
res.sendFile(path.join(__dirname, '../../dist/index.html'));
} else{
console.log("/app" + false);
res.redirect("/api/passport/login/facebook");
}
}
router.get('/app', checkAuthentication, (req, res) => {
console.log("approuter hit");
});
module.exports = router;
and go to '/app' directly. It'll still load the angular index.html page and not redirect you to log in. But if you go to '/' it will redirect you to log in.
How do i stop angular over-riding my NodeJS express routes?
UPDATE:
app.route.js snippet:
import { Routes } from '@angular/router';
import { HomeComponent } from './home';
export const ROUTES: Routes = [
{ path: '', component: HomeComponent },
];
You have to implement the AuthGuard and a Authentication service at client side( i.e. Angular) which will act as a communicator between client and server. Also keep a variable like isAuthenticated to track the login status.
AuthGuard :
import { Injectable } from '@angular/core';
import { CanActivate, CanActivateChild, Router } from '@angular/router';
import { AuthenticationService } from './auth.service';
@Injectable()
export class AuthGuard implements CanActivate, CanActivateChild {
constructor(private authService: AuthenticationService, private router: Router) {}
canActivate() : boolean {
console.log('AuthGuard#canActivate called ' + this.authService.isAuthenticated );
return this.checkLoggedIn("random");
}
canActivateChild() : boolean {
return this.canActivate();
}
checkLoggedIn(url: string): boolean {
if (this.authService.isLoggedIn()) {
return true;
}
this.authService.redirectUrl = url;
this.router.navigate(['/login']);
return false;
}
}
AuthenticationService:
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { Http, Response, Headers, RequestOptions } from '@angular/http';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { Observable } from 'rxjs/Rx';
import { NgForm } from "@angular/forms";
import { AuthenticationApi } from "../../modules/authentication/authentication-api";
import { IUser } from "app/modules/authentication/user";
var headers = new Headers({ 'Content-Type': 'application/json' });
var options = new RequestOptions({ headers: headers });
@Injectable()
export class AuthenticationService implements AuthenticationApi {
currentUser: IUser;
redirectUrl: string;
changePassoword: () => Observable<any>;
forgotPassowrd: () => Observable<any>;
isAuthenticated = false;
constructor(private router: Router, private http: Http) {
this.currentUser = null
}
isLoggedIn(): boolean {
return !!this.currentUser;
}
logIn(logInUser:any): Observable<any> {
console.log('UserService.signIn: ' + logInUser.userName + ' ' + logInUser.password + ' ' + logInUser.rememberMe);
this.isAuthenticated = true;
this.currentUser = {
userName: logInUser.userName
}
return this.http.post('http://localhost:3000/auth/login',
JSON.stringify(logInUser),
options
)
.map((resp: Response) => resp.json())
.catch(this.handleError);
//return Observable.of({}).delay(2000);
// return Observable.of({}).delay(2000).flatMap(x=>Observable.throw('Invalid User Name and/or Password'));
}
register(registerUser:any): Observable<any> {
this.isAuthenticated = true;
console.log(registerUser);
return this.http.post('http://localhost:3000/auth/register',
JSON.stringify(registerUser),
options
)
.map((resp: Response) => resp.json())
.catch(this.handleError);
//this.router.navigate(['/signin']);
//return Observable.of({}).delay(2000);
}
connectWithFacebook() :Observable<any> {
this.isAuthenticated = true;
//return Observable.of({}).delay(2000);
return this.http.get('http://localhost:3000/auth/facebook')
.map((resp: Response) => resp.json())
.catch(this.handleError);
}
connectWithGoogle() :Observable<any> {
this.isAuthenticated = true;
//return Observable.of({}).delay(2000);
return this.http.get('http://localhost:3000/auth/google')
.map((resp: Response) => resp.json())
.catch(this.handleError);
}
handleError(error: any) {
console.error(error);
return Observable.throw(error.json().error || 'Server error');
}
logOut(): Observable<any>{
this.isAuthenticated = false;
this.currentUser = null;
this.router.navigate(['/login']);
return Observable.of({})
}
}
AuthenticationApi: Common method to communicate
import { Observable } from 'rxjs';
export abstract class AuthenticationApi {
logIn : (loginUser:any) => Observable<any>;
logOut : () => Observable<any>;
register : (registerUser:any) => Observable<any>;
connectWithFacebook : () => Observable<any>;
connectWithGoogle : () => Observable<any>;
changePassoword : () => Observable<any>;
forgotPassowrd : () => Observable<any>;
}