Angular - navigating to a url after logging in - javascript

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.

Related

How to protect route in angular4

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;
}

Passing Value from RouterStateSnapshot to my Root Routing File in Angular 2 App

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.

how can i create MockActivatedRoute for the parent routes of ActivatedRoute in angular 4 Unit testing

Lets say I have a component that access parent route like this:
ngOnInit() {
this.sub = this.route.parent.parent.parent.params.subscribe(params => {
this.siteId = params["siteId"];
this.loadContents();
this.loadTypes(this.siteId);
});}
I m providing fake value for parent route like this:
providers: [
SiteService,
UserService,
Modal,
Overlay,
{
provide: ActivatedRoute,
useValue: { parent: { parent: { parent: { 'params': Observable.from([{ 'siteId': '156' }]) } } } },
},
OverlayRenderer,
AuthHttp,
MessageService,
],
it is giving me following error:
Failed: Cannot read property 'undefined' of undefined
AT line:
useValue: { parent: { parent: { parent: { 'params': Observable.from([{ 'siteId': '156' }]) } } } },
Please tell me what it is that i am doing in correct.
i have referenced following link:
How to mock an activatedRoute parent Route,
Testing Angular 2 parent route

Child route not found when redirected to, but works okay otherwise

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();
}

Angular 1.5 Component Routing from Server Side

I am looking to upgrade angular version to 1.5 and trying to figure out how I can do routing in Angular 1.5 Component Routing. Currently, we are doing as following using old angular router:
myApp.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when("/PP", {
templateUrl: function (route) {
var path;
var menuID = route.MenuID ;
$.ajax({
type: "POST",
async: false,
url: "./api/MyControllerName/MyControllerMethodName",
contentType: "application/json",
data: angular.toJson({
Action: 'NavigationManager.GetHtmlFilePath',
Data: { MenuID: menuID }
})
}).then(function (data) {
if (data.Success == true) {
var rte = $.parseJSON(data.Data);
path = rte.Route;
}
})
return path;
},
reloadOnSearch: false
})
.otherwise({ redirectTo: "/Home" });
}]);
The $.ajax call goes to server and gets the full path of the html file based on the MenuID from the url. Eventually content from this html file gets placed in ng-view.
All the examples of angular 1.5 component routing I have seen have hard coded path information as shown below:
angular.module('heroes', [])
.component('heroes', {
template: '<ng-outlet></ng-outlet>',
$routeConfig: [
{ path: '/', name: 'HeroList', component: 'heroList', useAsDefault: true },
{ path: '/:id', name: 'HeroDetail', component: 'heroDetail' }
]
})
My question is how do I replace the hard coded values with values coming from server just like I am doing with old angular router?
I had the same requirements. I had to set menus based on rights. My application is divided as a component tree. So, on login page, I set route registry as below:
class appOptions implements ng.IComponentOptions {
public controller: any;
public template: string;
public $routeConfig: any;
constructor() {
this.$routeConfig = [
{ path: '/', name: 'Login', component: 'login', useAsDefault: true },
{ path: '/workspace/...', name: 'Workspace', component: 'workspace' }
];
this.controller = appCtrl;
this.template = '<ng-outlet></ng-outlet>';
}
}
When user clicks on login button, I will get roles of users if authentication is passed. With successful authentication, server will pass JSON which will have list of permissions. Using that object to create routes. Calling below method in Login page
setRoute() {
this.myRoutes= this.routeService.getRoutes();
this.myRoutes.forEach((route) => {
this.$router.registry.config('workspace', route.route);
});
this.$router.navigate(['Workspace']);
}
routeService is the service which will actually generate routes
Now define interface based on parameter which are using for routing(eg:path, name, component, useAsDefault)
export interface IMyRoutes {
path: string;
name: string;
component: string;
useAsDefault: boolean
}
In controller of service:
public workspaceRoutes: app.IMyRoutes [] = []
getRoutes() {
this.accessProfile = this.userService.GetProfile();//This will get list of permission along with other details from server
if (this.accessProfile != null && this.accessProfile.Permissions.length > 0) {
this.accessProfile.Permissions.forEach((permission) => {
switch (permission) {
case "CanAccessMenu_1":
this.workspaceRoute = {
path: '/another_node_of_tree/...', name: 'Menu1', component: 'menu1', useAsDefault: (this.accessProfile.Role.toLowerCase() == "Role1")
}
this.workspaceRoutes.push(this.workspaceRoute);
break;
case "CanAccessMenu_2":
this.workspaceRoute = {
path: '/some_path/', name: 'Menu2', component: 'menu2', useAsDefault: (this.accessProfile.Role.toLowerCase() == "Role2")
}
this.workspaceRoutes.push(this.workspaceRoute);
break;
case "CanAccessMenu_3":
this.workspaceRoute = {
path: '/another_node_of_tree/...', name: 'Menu3', component: 'menu3', useAsDefault: (this.accessProfile.Role.toLowerCase() == "Role3")
}
this.workspaceRoutes.push(this.workspaceRoute);
break;
}
});
}
return this.workspaceRoutes;
}

Categories