Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CanActivate analogue in ui-router-ng2 1.0.0? #2964

Closed
kolkov opened this issue Sep 2, 2016 · 7 comments
Closed

CanActivate analogue in ui-router-ng2 1.0.0? #2964

kolkov opened this issue Sep 2, 2016 · 7 comments
Labels

Comments

@kolkov
Copy link

kolkov commented Sep 2, 2016

How can we create protected accsess in new ui-router-ng2 similar as in standard Angular 2 router?
http://blog.thoughtram.io/angular/2016/07/18/guards-in-angular-2.html#defining-guards

@christopherthielen
Copy link
Contributor

christopherthielen commented Sep 2, 2016

Using Transition Hooks.

Start with a simple transition hook function which asynchronously checks if the user is authenticated. It redirects to the login state if the user isn't authenticated.

The simple auth hook

function requireAuthentication(transition) {
  let $state = transition.router.stateService;
  let authSvc = transition.injector().get(AuthService);
  return authSvc.checkAuthenticated().catch(() => $state.target('login'));
}

Protect individual state

If protecting a single state, use an onEnter hook:

.state({
  name: 'foo',
  onEnter: requireAuthentication
})

Protect classes of states

If protecting a set or class of states, use a global hook which queries metadata on a state:

.state({
  name: 'foo',
  protectMe: true
});
class MyUIRouterConfig {
  configure(router: UIRouter) {
    let criteria = { entering: (state) => state.protectMe };
    router.transitionService.onBefore(criteria, requireAuthentication);
  }
}

Some other options:

Protect classes of states using data prop

The previous example could instead use the data property (which is inherited) to protect a tree of states. This allows protectMe metadata to be limited to the entry point of a state tree.

.state({
  name: 'foo',
  data: { 
    protectMe: true
  }
});

.state({
  name: 'foo.bar',
   // also protected because it inherits `data`
});
class MyUIRouterConfig {
  configure(router: UIRouter) { 
    let criteria = { to: (state) => state.data && state.data.protectMe };
    router.transitionService.onBefore(criteria, requireAuthentication);
  }
}

Protect group of states using globs

The hook could use state name globbing:

.state({
  name: 'authstates',
});

.state({
  name: 'authstates.bar',
   // also protected because it inherits `data`
});
class MyUIRouterConfig {
  configure(router: UIRouter) {
    let criteria = { to: 'authstates.**' };
    router.transitionService.onBefore(criteria, requireAuthentication);
  }
}

Hope this helps

@kolkov
Copy link
Author

kolkov commented Sep 2, 2016

Thank you for such a detailed answer!

@kolkov
Copy link
Author

kolkov commented Sep 2, 2016

I have a little problem. When transition rejected and state changed to public.user.login, the url is not changed to :8080/angular2/#/public/user/login

image

@christopherthielen
Copy link
Contributor

christopherthielen commented Sep 2, 2016

@kolkov please open a new issue. that sounds familiar and I think I know what the problem is.

  1. We track what triggers a transition (the trigger source). When triggered by a URL change, we don't update the URL.
  2. When we redirect a transition, we copy the .options() to the new Transition. I think this is copying the transition trigger as "url change"
  3. Your initial transition was triggered by a URL change (the initial call to .sync()).
  4. I think the redirected transition optiions still has "url" as the source, but it should be something else like "redirect".

Can you try stateService.target('public.user.login', null, { source: 'unknown' }) and see if the URL updates?

Here's where we create the redirected transition options: https://github.com/angular-ui/ui-router/blob/master/src/transition/transition.ts#L374

@kolkov
Copy link
Author

kolkov commented Sep 2, 2016

Can you try stateService.target('public.user.login', null, { source: 'unknown' }) and see if the URL updates?
Yes! This worked!

@pscanlon1
Copy link

return authSvc.checkAuthenticated().catch(() => $state.target('login'));

is this a promise? what do i need to return here...

@christopherthielen
Copy link
Contributor

@pscanlon1 in the example, authSvc.checkAuthenticated() is a fictional service call that would return a promise for whether the user is authenticated or not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants