Angular 2 How to Apply Multiple Guards with Or-Relationship on the Same Path
Asked Answered
P

2

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!

Pantoja answered 1/4, 2017 at 23:20 Comment(4)
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...Ewen
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.....Pantoja
Yeah I know, I have the exact same problem... Waiting for someone to give you a real solution ;)Ewen
Then could you please vote this question up, so that this question receives attention, thanks! :-)Pantoja
H
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 :)

Hodges answered 7/12, 2017 at 15:36 Comment(0)
S
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 (;

Stickinthemud answered 1/4, 2017 at 23:33 Comment(4)
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 workMercia
@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!Pantoja
Sorry, I've been super busy.Mercia
See this question: #40590378 and specifically the answer from tvoloshyn which may provide a solution to your problem.Rosenfeld

© 2022 - 2024 — McMap. All rights reserved.