18

My application allows access to contents based on user roles. I wrote a Router Guard for each role. Some contents allow access for role1 or role2 or role3. How should I write that canActivate declaration in the feature-routing.module.ts file? As I understand, if I write

canActivate:[Role1Guard, Role2Guard, Role3Guard]

The access will be denied if any of the guards returns false. But in my case, I should allow access if any of the guards returns true. How to do it? Many thanks in advance!

Nicole Naumann
  • 1,018
  • 2
  • 10
  • 23
  • 1
    The easy solution is to create a guard that takes the 3 roles into account, that's what I do for the moment, Role1or2or3Guard, but I'd love a nicer solution where I can combine my existing guards... – Seb Apr 06 '17 at 06:02
  • Yes I thought about this solution too. For one case this will work, and pretty simple to implement. Problem only occurs when you want to generalize it....if you have 5 roles and every combination is possible, you need a robot to write all the guard classes..... – Nicole Naumann Apr 06 '17 at 20:50
  • 2
    Yeah I know, I have the exact same problem... Waiting for someone to give you a real solution ;) – Seb Apr 07 '17 at 09:16
  • Then could you please vote this question up, so that this question receives attention, thanks! :-) – Nicole Naumann Apr 07 '17 at 09:20

2 Answers2

2

What we can do in this case is create a Master Guard which will trigger the application guards as per our requirement.

Checkout this answer to understand the approach.

Assuming you have gone through it above link, the approach in this case could be as simple as modifying the data property in Route class.

Something like this -

{
    path: "view2",
    component: View2Component,
    //attach master guard here
    canActivate: [MasterGuard],
    //this is the data object which will be used by 
    //masteer guard to execute guard1, guard 2, guard 3 & guard 4
    data: {
        trigger: {
            operator: "OR",
            guards: [
                GUARDS.GUARD1,
                GUARDS.GUARD2,
                GUARDS.GUARD3,
                GUARDS.GUARD4
            ]
        }
    }
}

And then use operator flag to fire all guards accordingly.

I hope this helps :)

Community
  • 1
  • 1
planet_hunter
  • 3,866
  • 1
  • 26
  • 39
1

You could write OrGuard, something like:

class OrGuard() {
  guards: any[];
  constructor(...guards) { this.guards = guards }

  canActivate() {
    return this.guards.some(Boolean);
  }
}

and use it like this:

canActivate:[new OrGuard(Role1Guard, Role2Guard, Role3Guard)]

...just an idea, actual implementation might be different, I didn't try (;

Sasxa
  • 40,334
  • 16
  • 88
  • 102
  • 5
    This won't work if the guards have any dependencies. For example if they need to make HTTP requests. A service or a class factory would work – Aluan Haddad Apr 02 '17 at 00:39
  • @Aluan Haddad, could you please elaborate a little bit? How to do it with service and how to do it with class factory? Many thanks in advance! – Nicole Naumann Apr 02 '17 at 10:25
  • Sorry, I've been super busy. – Aluan Haddad Apr 05 '17 at 12:19
  • See this question: https://stackoverflow.com/questions/40589878/multiple-canactivate-guards-all-run-when-first-fails?noredirect=1&lq=1 and specifically the answer from tvoloshyn which may provide a solution to your problem. – rmcsharry Sep 18 '17 at 10:59