I have Login/Create Account in My application. I want the user will not be able to see login/create account if user is already logged in.
I am using an Authguard to protect the route:
#Injectable()
export class AuthGuard implements CanActivate {
constructor(private router: Router) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {debugger;
if (localStorage.getItem('UserLoggedIn')) {
// logged in so return true
this.router.navigate(['']);
return true;
}
// not logged in so redirect to login page with the return url
this.router.navigate(['login']);
return false;
}
In this case the page is going in infinite loop.
This is my Routes:
const appRoutes: Routes = [
{ path: '', component: HomeComponent , data: { animation: '' }},
{ path: 'login', component: UserloginComponent , data: { animation: 'login' },canActivate:[AuthGuard]},
{ path: 'create-account', component: CreateAccountComponent, data: { animation: 'create-account' } },
{ path: 'forgot-password', component: ForgotPasswordComponent, data: { animation: 'forgot-password' } },
{ path: '**', component: PageNotfoundComponent }
];
Please Help. I want it for login and create account.
It is because you added this.router.navigate(['login']); to your authguard and this authguard was attached to login route. Each time a route was accessed it always call all the guards that was attached. So in your case if you access login, it will infinitely redirect to login. There are many ways to solve your issue. If you are intending to add the guard on the login route, just remove this.router.navigate(['login']); to avoid infinite loop. But i suggest to add the guard only to those routes you want to protect being accessed at if the user is not logged in.
Try this:
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {debugger;
let redirect: boolean = false;
if (localStorage.getItem('UserLoggedIn')) {
// logged in so return true
this.router.navigate(['']);
redirect = true;
} else {
// not logged in so redirect to login page with the return url
this.router.navigate(['login']);
redirect = false;
}
return redirect;
}
Related
For example I have a url and I input it on the browser https://developer.anduks.myproperties/#/myproperties/3664-S
If I’m not logged in, it should take me to the login page which is currently working on my end. But, after I login, it doesn’t take me to the link I inputed on the browser like the sample link
When I input the url in the browser and I am not logged in then redirect to login page . If I input the url on the browser and hit enter and then I logged in my account it should redirect to that url input.
Anyone has an idea how to implement the problem above? Thanks.
#auth.guard.ts code
export class AuthGuard implements CanActivate {
userProfile: any;
constructor(private authService: AuthService, private route: Router,) {}
public async canActivate(route: ActivatedRouteSnapshot): Promise<boolean> {
const allowedUserRoles = this.getRoutePermissions(route);
return await this.checkPermission(allowedUserRoles);
}
private getRoutePermissions(route: ActivatedRouteSnapshot): Roles[] {
if (route.data && route.data.userRoles) {
return route.data.userRoles as Roles[];
}
return null;
}
private checkPermission(allowedUserRoles: Roles[]): Promise<boolean> {
return this.authService.getSession().then((session: boolean) => {
if (session) {
if (!allowedUserRoles) {
return true; // if no user roles has been set, all user are allowed to access the route
} else {
let userRoles = JSON.parse(localStorage.getItem("userRoles"));
if (this.authService.areUserRolesAllowed(userRoles, allowedUserRoles)) {
return true;
} else {
this.route.navigateByUrl('/transactions');
return false;
}
}
} else { return false; }
});
}
}
#app-routing.module.ts
const routes: Routes = [
{
path: '',
component: DashboardComponent,
canActivate: [AuthGuard],
children: [
{
path: 'properties',
loadChildren: () => import('./features/property/property.module').then(m => m.PropertyModule),
data: {
userRoles: [Roles.ADMIN, Roles.TRANSACTION_SUPER_USER, Roles.TRANSACTION_MANAGER]
},
},
{
path: 'settings',
loadChildren: () => import('./features/settings/settings.module').then(m => m.SettingsModule),
data: {
title: 'Settings',
userRoles: [Roles.ADMIN, Roles.TRANSACTION_SUPER_USER, Roles.TRANSACTION_MANAGER]
}
},
{
path: 'transactions',
loadChildren: () => import('./features/transactions/transactions.module').then(m => m.TransactionsModule),
data: {
title: 'Transactions',
userRoles: [Roles.BROKER, Roles.ADMIN, Roles.TRANSACTION_SUPER_USER, Roles.TRANSACTION_MANAGER]
}
},
]
},
{
path: 'login',
component: LoginComponent,
},
{
path:'**',
redirectTo: ''
}
];
#NgModule({
imports: [
RouterModule.forRoot(routes, {
useHash: true,
preloadingStrategy: PreloadAllModules,
}),
],
exports: [RouterModule]
})
I would create service BeforeAuthRedirectionService. It would have private property url and getter/setter. when you are returning false in canActivate guard ( when user is not logged in ) before user gets redirected to login page you have to save current url and set it in your service. after login happens you can acess that url again and redirect to that page.
I am trying to figure out how to pass the value from the RouterStateSnapshot in my auth.guard file to my routing file in my Angular 2 app. I want to do this because, rather than loading a hard-coded default component first, I want, after re-login, for the last active component/page to load up. I have this value in my canActivate() function in my AuthGuard file, because I can console out it out via RouterStateSnapshot. So now I need to figure out how to pass this value on to my root routing file so it, on login/re-login, that component gets loaded.
This is the canActivate() function in my AuthGuard file:
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot)
{
// Get route content id
let contentId = Object.getPropertyValueAtPath(route, 'data.contentId');
console.log(state.url);
// If route does not have session id, don’t load in tab view
if (!String.isNotNullOrEmpty(contentId))
{
console.error(`Route (${route.routeConfig.path}) does not have a content id.`);
this.router.navigateByUrl(''); // Forward to default page.
this.router.navigate([state.url]);
return false;
}
if (this.disabled) return true;
if (sessionStorage.getItem('currentUser'))
{
// logged in so return true
return true;
}
// not logged in so redirect to login page with the return url
this.router.navigate(['/login', {returnUrl: state.url}]);
return false;
}
Notice that I am doing this within that function: console.log(state.url). This gives me the correct value. Now I need to pass it to my app-routing file.
To clarify, currently, on re-login, the last active component is loaded -- but it displays as a background tab, and the default 'redirect' component is what loads up as the active component (i.e, it shows as the active tab).
A simplified version of the app-routing file looks like this:
import { HomeComponent } ...
export const routes: Routes = [
{ path: 'login', component: LoginComponent },
{ path: 'home', component: HomeComponent },
{ path: 'about', component: AboutComponent },
{ path: '**', redirectTo: 'home' }
];
As you can see above, on initial load I currently redirect the user to the 'home component' by default. What I'd like to do is re-direct them to the value that is stored in "state.url" from RouterStateSnapshot. I'm not clear how to do this, however. Any ideas as to how I'd pass that value from my AuthGuard file down to my app-routing file? Can I simply inject RouterStateSnapshot into my app-routing file to get that desired value directly? Or can I use "resolve" here along with the path in routing? What's the recommended way to handle this kind of scenario?
I accomplish this by storing the url in a shared service from my AuthGuard
// auth-guard.ts
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
let isLoggedIn = this.authService.isUserLoggedIn();
if(isLoggedIn){
return true;
}else{
this.someService.storeRedirectUrl(state.url);
this.router.navigateByUrl('/login');
return false;
}
}
Then when the user logs in, check if that redirect url was stored and navigate to it
// login method within login page
login(){
this.authService.login(email, password).subscribe(
res => {
// successful user login, so determine where to route user
if(this.someService.redirectUrl){
// redirect url found, navigate to that url
this.router.navigateByUrl(this.someService.redirectUrl);
}else{
// if no redirect url found, navigate to normal landing page
this.router.navigateByUrl('/home');
}
});
}
Routes File
// routes
export const routes: Routes = [
{
path: 'login',
component: LoginComponent
},
{
path: 'home',
component: HomeComponent,
canActivate: [AuthGuard]
},
{
path: 'about',
component: AboutComponent,
canActivate: [AuthGuard]
},
{
path: '**',
redirectTo: 'home'
}
];
Can I simply inject RouterStateSnapshot into my app-routing file to get that desired value directly?
app-routing is just for mapping routes to components, so there is no injecting the route snapshot into it.
Another option you could do is to pass the redirect url as a query parameter of the login page within the auth guard. (I think this was what you were heading towards)
// auth-guard.ts
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
let isLoggedIn = this.authService.isUserLoggedIn();
if(isLoggedIn){
return true;
}else{
this.router.navigate(['/login', {redirectUrl: state.url}]);
return false;
}
}
Then the process is the same after a user logs in successfully, except this time you fetch the redirect url from the url parameters instead of the service.
I have this requirement for my website. The website will be a SPA built with Angular 2.
What I want is that the user can login using Google, Facebook, Twitter oauth.
I can setup the oauth on the node server, but the problem is how do I allow login through angular 2 app.
In the angular 2 app if when the user clicks facebook signin option, I cant redirect the user as then I lose the state of my application.
I dont know if this is a very beginner problem. Can anyone help me with the flow of what happens in angular 2 + node oauth
You are going to want to setup routes in the angular app to handle the front end of your application. Then create a service to handle the auth0 authentication of the application,
This is a overview of setting up a secure set of routes and a public set of routes in your app. Once someone logs in with oauth they will be forwarded to the secure routes.
So starting out here is the routes. We will specify a secure and public in the app.routing.ts file
Routes
const APP_ROUTES: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full', },
{ path: '', component: PublicComponent, data: { title: 'Public Views' }, children: PUBLIC_ROUTES },
{ path: '', component: SecureComponent, canActivate: [Guard], data: { title: 'Secure Views' }, children: SECURE_ROUTES }
];
Ok so now that you have that. You can create a templates directory. Inside create secure.component and public.component. Then I create a directory called secure and one called public which I put all of my components dependent on the authentication level to access them. I also add their routes to a file in those directories to keep everything separate.
Notice in my routes above I have the [Guard] setup on the secure. This will block anyone from going to the secure routes without authentication.
Here is an example of what that guard looks like.
import { Injectable } from '#angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '#angular/router';
import { Auth } from './auth.service';
import { Observable } from 'rxjs/Observable';
#Injectable()
export class Guard implements CanActivate {
constructor(protected router: Router, protected auth: Auth ) {}
canActivate() {
if (localStorage.getItem('access_token')) {
// logged in so return true
return true;
}
// not logged in so redirect to login page
this.router.navigate(['/home']);
return false;
}
}
Now that we have that we have the routes secured with Guard. We can setup the auth0 client.
Create a config file with your credentials you get from auth0
interface AuthConfiguration {
clientID: string,
domain: string,
callbackURL: string
}
export const myConfig: AuthConfiguration = {
clientID: 'clietnifherefromauth0',
domain: 'username.auth0.com',
// You may need to change this!
callbackURL: 'http://localhost:3000/endpoint/'
};
Then to actually authenticate someone. Receive their data and save the token as well as their data to the local storage. Also provide a logout function and a check to make sure they are logged in.
import { Injectable } from '#angular/core';
import { tokenNotExpired, JwtHelper } from 'angular2-jwt';
import { Router } from '#angular/router';
import { myConfig } from './auth.config';
declare var Auth0Lock: any;
var options = {
theme: {
logo: '/img/logo.png',
primaryColor: '#779476'
},
languageDictionary: {
emailInputPlaceholder: "email#example.com",
title: "Login or SignUp"
},
};
#Injectable()
export class Auth {
lock = new Auth0Lock(myConfig.clientID, myConfig.domain, options, {});
userProfile: Object;
constructor(private router: Router) {
this.userProfile = JSON.parse(localStorage.getItem('profile'));
this.lock.on('authenticated', (authResult: any) => {
localStorage.setItem('access_token', authResult.idToken);
this.lock.getProfile(authResult.idToken, (error: any, profile: any) => {
if (error) {
console.log(error);
return;
}
localStorage.setItem('profile', JSON.stringify(profile));
this.userProfile = profile;
this.router.navigateByUrl('/CHANGETHISTOYOURROUTE');
});
this.lock.hide();
});
}
public login() {
this.lock.show();
}
private get accessToken(): string {
return localStorage.getItem('access_token');
}
public authenticated(): boolean {
try {
var jwtHelper: JwtHelper = new JwtHelper();
var token = this.accessToken;
if (jwtHelper.isTokenExpired(token))
return false;
return true;
}
catch (err) {
return false;
}
}
public logout() {
localStorage.removeItem('profile');
localStorage.removeItem('access_token');
this.userProfile = undefined;
this.router.navigateByUrl('/home');
};
}
Make sure to go into your auth0 dashboard and select the social links you want. In your case facebook twitter and Google. Then when someone activates the widget those three will appear.
So all we have to do now is show the widget when someone clicks login,
html will show a login link. But if they are logged in it will show a bit of information about them instead.
<ul class="nav navbar-nav pull-right">
<li class="nav-item">
<a class="nav-link" (click)="auth.login()" *ngIf="!auth.authenticated()">Login / SignUp</a>
<a class="aside-toggle" href="#" role="button" aria-haspopup="true" aria-expanded="false" *ngIf="auth.authenticated()">
<span *ngIf="auth.authenticated() && auth.userProfile" class="profile-name">{{auth.userProfile.nickname}}</span>
<span *ngIf="!auth.authenticated() && !auth.userProfile" class="profile-name">Account</span>
<i class="icon-bell"></i><span class="tag tag-pill tag-danger profile-alerts">5</span>
<img *ngIf="auth.authenticated() && auth.userProfile" [src]="auth.userProfile.picture" class="img-avatar profile-picture" alt="User profile picture">
<img *ngIf="!auth.authenticated() && !auth.userProfile" src="/img/avatars/gravatar-default.png" alt="Default profile-picture">
</a>
</li>
</ul>
Let me know if anything is not clear. I would be glad to help.
I am having an issue with child routers/routes. (Abbreviated example below.)
app.ts
config.map([
{ route: "auth", name: "auth", moduleId: "auth" }
]);
auth/index.ts
config.map([
{ route: "", redirect: "login" },
{ route: "login", name: "login", moduleId: "./login", title: "Login" }
]);
authentication-step.ts
run(navigationInstruction, next) {
if (navigationInstruction.getAllInstructions().some(i => i.config.auth)) {
if (!this.authContext.isAuthenticated())
return next.cancel(this.router.navigateToRoute('auth/login', { return: true }));
}
return next();
}
If a secured route is requested, I have an AuthenticationStep which will redirect to auth/login. This does not work, for instance, if I try to go to a secured route (e.g. admin/something) I get the error below. However, if I navigate directly to auth/login, the login page shows up correctly.
A route with name 'auth/login' could not be found.
Add an empty route with a redirect to your child router's configuration:
{ route: '', redirect: 'login' }
Then, change your call to navigateToRoute to navigate to auth.
run(navigationInstruction, next) {
if (navigationInstruction.getAllInstructions().some(i => i.config.auth)) {
if (!this.authContext.isAuthenticated())
return next.cancel(this.router.navigateToRoute('auth', { return: true }));
}
return next();
}
I'm using ReactJS and react-router in my application. I need to do next thing: when user open the page - to check, if he logged in or no, and if yes, then to do redirect to /auth page. I'm doing next thing:
componentWillMount: function() {
if (sessionStorage["auth"] == null) {
this.transitionTo("/auth");
}
},
In browser url it really do redirect to /auth, render the /auth page and after override it with current component. So here the question: how to cancel rendering for the current component, or how to do redirect in other way? Thanks.
Take a look at the react-router example auth-with-shared-root: https://github.com/rackt/react-router/tree/master/examples/auth-with-shared-root
What they basically do is to check on an enter of a route where to go. Take a look in file config/routes.js line 36, 51 and 89:
{ onEnter: redirectToLogin,
childRoutes: [
// Protected nested routes for the dashboard
{ path: '/page2',
getComponent: (location, cb) => {
require.ensure([], (require) => {
cb(null, require('../components/PageTwo'))
})
}
}
// other protected routes...
]
}
This route will call function redirectToLogin when the route /page2 is entered or pushed to. The function can than check, if the user is authenticated with auth.loggedIn()
function redirectToLogin(nextState, replace) {
if (!auth.loggedIn()) {
replace({
pathname: '/login',
state: { nextPathname: nextState.location.pathname }
})
}
}
If the user is not logged in, the function will replace the route to /login, where the user can authenticates itself.