ReactJS redirect - javascript

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.

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.

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

How to ignore trailing slash in marionette routes?

I am defining routes in Marionettejs as follows:
var Mn = require('backbone.marionette');
var Router = Mn.AppRouter.extend({
routes: {
'': 'default',
'login': 'login', // http://localhost:8080/#/login
'signup': 'signup' // http://localhost:8080/#/signup
},
initialize: function () {
var initData = this.getOption('keyInOptions');
},
// below are route functions
default: function () {
console.log('this is default route');
},
login: function () {
console.log('this is login route');
},
signup: function () {
console.log('this is signup route');
}
});
module.exports = Router;
Then in the browser:
http://localhost:8080/#/login
successfully triggers the login route, but
http://localhost:8080/#/login/
(add one forward slash at the end) will not trigger login route function. I know I can define another route entry:
...
'login': 'login',
'login/': 'login',
...
to solve this problem, but this solution will double the entries in router definition. Is there a better way to trigger the same route handler for login and login/ ?
Have you tried surrounding the trailing slash with parentheses? Like the following:
routes: {
'login(/)': 'login'
}
From the backbone documentation:
Part of a route can be made optional by surrounding it in parentheses
(/:optional).

Doing something different for main route in meteor iron router

Im using Iron-Route for routing in my meteor app. As I have multiple modules and I want to avoid multiple coding, I put the filter for authentification (role) to the core package:
core package
var filters = {
authenticate: function () {
var user;
if (Meteor.loggingIn()) {
this.layout('login');
this.render('loading');
} else {
user = Meteor.user();
if (!user) {
this.layout('login');
this.render('signin');
return;
}
this.layout('StandardLayout');
this.next();
}
}
}
Router.configure({
layoutTemplate: 'layout',
loadingTemplate: 'loading',
notFoundTemplate: 'notFound',
before: filters.authenticate
});
Router.route('/', function () {
this.render('contentTemplate', { to: 'content' });
this.render('navigationTemplate', { to: 'navigation' },)
});
other packages
...just need this:
Router.route('/article/:_id', {
name: 'article',
yieldTemplates: {
'navigationPage': { to: 'navigation' },
'contentPage': { to: 'content' }
}
});
Now there is a check on every module (route) before displaying anything.
But I need an exception for the front page. The main page Route.route('/') should be accessed also by user who are not logged in. How do I do that?
You can use the onBeforeAction hook from iron:router as shown below.
This solution assumes your login route is named 'login' . But can be modified to fit your needs.
./client/lib/hoooks/router.js
Router.onBeforeAction(function () {
// all properties available in the route function
// are also available here such as this.params
if (!Meteor.userId()) {
//code for action to be taken when user is not logged in
this.redirect('login');
this.stop();
} else {
this.next();
}
},{except: ['homeRouteName'] });
NB: Replace 'homeRouteName' with the name of your route at '/'

Categories