3

A common recommended way to secure Angular 2 component/routes seems to be to use @CanActivate(), like here:

http://youknowriad.github.io/angular2-cookbooks/stateless-authentication.html

If you have only a few components this works fine, but is there a better way that would centralize all this?

Would having a common base class for each component work? (any examples on how to do this?). Could we have a custom @CanActivate(), something like @ProtectMyApp()? (examples?)

I'm basically trying to prevent having to copy+paste the same @CanActivate() code for each component.

(apologies if these questions do not make sense, still learning Angular)

Thanks

pbz
  • 8,865
  • 14
  • 56
  • 70
  • 1
    Possible duplicate of http://stackoverflow.com/questions/34754295/angular2-router-anyone-know-how-to-use-canactivate-in-app-ts-so-that-i-can-red/34759270?noredirect=1#comment57283408_34759270 – inoabrian Feb 04 '16 at 02:04
  • @inoabrian yes, that's very close to what I'm after. Unfortunately, I wasn't able to use that, getting "Cannot resolve all parameters for 'Router'(?, ?, ?)" – pbz Feb 04 '16 at 14:22

1 Answers1

6

You can create a global callback that you can pass into the @CanActivate decorator:

export function isAllowed(): boolean | Promise<boolean>{
    // Permission logic here
}

and then you can pass that function into the decorator

@Component({...})
@CanActivate(isAllowed)
export class MyComponent{

}

This would give you a global source of validating permission, but still use the built in methods.

Update

This is untested but might work for injecting a service into isAllowed

In the documentation I found that the bootstrap method returns a ComponentRef which has an injector property that has the following comment in the docs

The injector provided DynamicComponentLoader.

This could be the golden ticket for getting the same singleton instance that is used by the main injector for the application. In theory this should work

In your startup file

export var applicationInjector: Injector;
bootstrap(AppComponent, [MyService, ...]).then((ref: ComponentRef) => {
    applicationInjector = ref.injector;
});

Then in the file with your isAllowed method

import {applicationInjector} from '...';

export function isAllowed(): boolean | Promise<boolean>{
    let myService: MyService = applicationInjector.get(MyService);
    return myService.isAllowed();
}
SnareChops
  • 13,175
  • 9
  • 69
  • 91
  • Ideally, I would like to use a service that I would inject into "isAllowed()". Is that possible? – pbz Feb 04 '16 at 02:27
  • I'm sure it is, but I haven't yet figured out how to hack into the `Injector` of the running application. You could of course use your own `Injector` or simply `new` the service yourself. But that would then be a different instance then the one running elsewhere in your application. – SnareChops Feb 04 '16 at 02:33
  • Actually I just found something that might work, but I don't really know, haven't tried it. I'll update my answer with the code. – SnareChops Feb 04 '16 at 02:33