Playing
01. Impersonating users in Laravel

Episodes

0%
Your progress
  • Total: 14m
  • Played: 0m
  • Remaining: 14m
Join or sign in to track your progress

Transcript

00:00
If you need to give admins permission to impersonate users and take actions on their behalf, this is actually pretty simple to do.
00:07
Now in the past, I've taken the approach by using auth and login using ID. Now this is a really bad idea and I'm going to tell you exactly why this is throughout the course and we're going to look at a really nice way to do this. So login using ID is pretty straightforward.
00:24
You'd probably post a form, pass the user's ID in that you want to impersonate and that would sign you in as that particular user. Like I said, this isn't the best solution. So let's take a look at a really good solution to get this working.
00:36
Now just to demo this out, I'm currently signed in as a user here and I want to go ahead and impersonate another user. So let's take a look at how this works. We're going to build out a really simple form where we can enter the user's email address.
00:47
We can click impersonate and that's going to go ahead and allow us to be signed in as them, update their profile and do whatever we need to in their account. Now you'll notice that up here we have a stop impersonating button. What it's done is it's detected that I'm signed in as this user
01:02
but it hasn't actually taken over the session as that user. We're actually implementing some middleware to control this and we'll be seeing that in a bit. So this gives me the advantage of being able to click stop impersonating and return me back to my admin account.
01:16
We're not going to look at roles and permissions in this course but we do have a course on that if you want to tie this in to only allow admins to impersonate users. So that's pretty much what we're covering.
01:26
Let's go and look at how we build this solution up. Okay, so we're starting out here with a fresh Laravel installation. I've got two users inside the database. Of course, I've already migrated all the default tables that we have here.
01:37
That's pretty much all we need to work with. So the first thing that we're going to do is create the controller that will allow us to actually start the impersonation process and this will give us a good idea as to how this is all going to come together.
01:49
So let's go ahead and create this controller inside of our controllers directory. So we're going to make a controller inside of admin and we're going to call this impersonate controller. Of course, you can call this whatever you want.
02:02
Okay, so let's open this up and the first thing that we want is an index page to go ahead and show that form to actually enter an email address to impersonate a particular user by their email and of course, you can update this to obviously taking an ID
02:17
or any other information about a user. Okay, so let's go over to our web routes and we are going to just duplicate this route down and I'm going to go ahead and create a kind of admin area.
02:28
What you'd of course want to do is protect these routes with some kind of route middleware and you can find all of that information out if you want to in the roles and permissions course. So let's go into admin and we're going to use the impersonate controller that we've just created. We can get rid of the name of this for now.
02:43
We don't really need it. Let's just change this over actually. So we'll say admin.impersonate. I think that makes sense.
02:49
Okay, so let's change the name of this route over actually and that should be just about it. So of course, we need to create our view in here. So let's create that admin folder.
02:58
Let's go ahead and create the impersonate.blade.php file and let's just go ahead and write anything in here just to test this out. Okay, so as an admin now, I should be able to come over here and see this page. Perfect, that's all working.
03:12
Let's go ahead and copy the structure for the homepage over to here very quickly. Just indent this and we'll say impersonate a user, whatever you want to say. And inside of here will just be a form to go ahead and enter an email address. So let's start to build this out really quickly.
03:29
We're going to have a form group inside of here. This is going to have an input with the type of text. We can add a label just above this as well. And this will be the email address for the user.
03:39
Although like I said, you could switch this up to use an ID or any other identifier. And that should be just about it. Let's just go ahead and create a submit button down here with impersonate. And let's add a couple of classes here just so we get some nice bootstrap styling in.
03:53
And this one will have a class of form control. Okay, so let's switch over and this is pretty much our form. So of course we need to submit this through. So we are going to create a store method in here.
04:06
And this is where we get to start to see how this functionality is going to work. So let's bring in our request object in here. Now inside of here, we of course want to validate this because we need to say that the email is required.
04:20
We want to check it's actually an email address. Really importantly, we want to check it exists in the users table. So I'm just going to add some really simple validation here. I'd recommend you extract this out to a form request.
04:31
But you know, it's not the end of the world. Let's go ahead and say that the email is required. And let's say it has to be an email, of course, unless you're changing over to accept an ID. And let's say it exists in the users table under email.
04:44
So that should nicely validate that. I'm not going to add form validation output to the actual form itself. But you can go ahead and do that if you want to. So if we come over to our web route then and just duplicate this down,
04:55
we can get rid of the name because it's going to inherit that name. And let's post through to this and use that store method. And let's come over to impersonate and update the form just in here. So let's give this a root with the name of admin impersonate, like so.
05:11
And of course, let's include the post method in here. And really importantly, the cross site request forgery field that we need as well. Okay, so now I should be able to go ahead and type in an email address. So for example, the other user in here, and that should lead me through to a blank page.
05:27
And of course, if this doesn't exist, or it's not a valid email, we're redirected back. So let's go ahead and grab this user. Like I said, if you are using soft deletes, you're going to want to use with trashed. That would involve over on your user model having the soft deletes trait added,
05:42
and also having that set up in your database. Now I don't have that set up at the moment. But if you did want to allow admins to log in as people that have been soft deleted, then of course, you're going to want to add that in.
05:53
So what I'm going to do is look this user up by their email address. And of course, you can add another where clause in here if you're allowing this by ID. And we're just going to go ahead and grab the first user. At this point, we should know that that user does exist because we've included it
06:06
in our validation rules. Now here's where the magic comes in. What we're actually going to do now is using our session helper, we're going to put into a key called impersonate that user's ID.
06:17
And then we're going to go ahead and return. And we're going to redirect back to the homepage just really simply. Now the reason that we're doing this is because technically now this is kind of out of the way. And we can start to introduce some middleware to temporarily sign that user in
06:32
or that admin in as this user. What we're not doing is using auth login using ID because that would completely overwrite the session. So that's what we're doing.
06:44
If we go ahead and enter Dale's email address here and click impersonate, of course, we just need to pull the user model into here. Let's give that another refresh. And sure enough, we redirected back home.
06:54
Now nothing is different at the moment, but we're now in the position to introduce that middleware I was speaking about. So let's come over and generate some middleware and see how this works. So we're going to make some middleware.
07:05
And I'm going to put this in an admin folder. And I'm going to call it impersonate. Okay, so once this has been created, let's come over here and see what we can do. Now at this point, all we really need to do is check if the session has an impersonate
07:20
value in there. So we just need to use the session helper again. And we can say has impersonate. Well, if that's the case, we want to go ahead and temporarily sign that user in.
07:29
Now, really importantly, we have a method on the auth class called once using ID. And this allows us to grab the impersonation ID from the session and authenticate us just once. So that means that the entire session won't be overridden.
07:46
It just will be for that particular session as we refresh the page. So let's bring the auth facade in here. And what I'm going to do is come over to the kernel and register this. Now, as a really important note, what you could technically do is include this as root
08:00
middleware and only allow admins to impersonate particular sections of your site. What I'm going to do is go ahead and add it as global web middleware because I just want to assume that all users or all admins should be able to access all areas of the site as a signed in user.
08:17
But like I said, add it to root middleware if you want to restrict this. Okay, so if we just come over here and give this a refresh, it looks like auth isn't found. So let's go ahead and pull this in to here. This, of course, shouldn't be middleware.
08:30
This should be the facade for auth. Let's come over to the browser, give that a refresh. And sure enough, we're signed in as Dale. Now, however much I navigate the site, it's always going to sign me in as Dale because
08:41
that middleware is being run for every single request. The only problem now is we have no real way to get out of this unless we sign out, which we don't really want to do because that's going to log Dale out. And then we're just going to have to log in as ourselves again.
08:53
So let me just go ahead and log back in. And we're going to go ahead and impersonate this user once again. Let's come over here into that email address and click impersonate. We're signed in as Dale now.
09:04
But how do we get out of this? Well, what we can do is up in the navigation, include a link to stop impersonating as we've already seen. So let's open app.blade.php.
09:15
Now, there's a couple of ways that you could do this. If, for example, you'd find it useful to have an impersonation check to see whether an admin is impersonating user elsewhere on the site, you could include a blade directive for this. And that's exactly what we're going to be doing here.
09:30
If you're not too worried about that, what you could do is just say if session has. So we could say has impersonate like so. Then we want to go ahead and output a link. So we're going to create a list item inside of here with an anchor.
09:45
And we're going to say stop impersonating like so. So this is going to go ahead and submit a form, a hidden form, and stop the impersonation process. Now, the only problem with this is if we want to, like I said, use this check elsewhere
09:59
and then, for example, we change the name of the key for the impersonation, we're going to have to go and update this everywhere. So I'm going to switch this out for a blade directive. I much prefer doing this.
10:08
It also tidies up our code as well. So let's go ahead and make a service provider. And I'm going to call this blade service provider like so. And let's come over to that blade service provider.
10:20
And inside of here, we're going to use blade to create an if statement called impersonating. And this has a closure just in here, which returns either true or false based on whether we should show the content in between this custom directive. Now, in this case, all we need to do is use this once here.
10:38
So we just say session has impersonating. And you could also add some kind of other check in there if you wanted to. Now, if we come over or make sure you pull the blade namespace in first and we come over to config an app and register this.
10:50
So let's do this just under here, that application service providers. So let's switch this out for blade service provider. What we can now do is use impersonating and end impersonating in here really nicely. So impersonating.
11:05
And then we can take the same thing and say end impersonating. And that's going to have exactly the same effect. Now, at the moment, it's disappeared because I need this to be impersonate, not impersonating, but you kind of get the idea.
11:17
So what we can now do is look at stopping impersonating. Now, you could have this as a get route where you just click it. But what I'm going to do is include a hidden form here to stop the impersonation process, really just so we can take advantage of having a cross-site request forgery token.
11:33
It's not really the end of the world, but it's really important that for me, at least, I always include cross-site request forgery whenever I'm updating something like this. So what I'm going to do is create a hidden form in here with an ID of impersonating or stop impersonating, whatever you want.
11:48
And this is going to go through to the admin impersonating. I think we called it that. Let's just head over to our routes. It's impersonate.
11:58
So we need to make sure we distinguish between these. And basically, that's just going to go ahead. And when we click on this, submit that form, much like the logout menu does or logout button just does here in the menu.
12:10
So let's include here a cross-site request forgery field, whole point of doing this. And let's also include a method field as well. Because what I want to do is make sure that this sends a delete request through a forged or spoofed delete request.
12:23
So we haven't actually set up this route yet. And we haven't set up the method. So let's go ahead and do this now. Let's say delete admin impersonate.
12:29
And let's call the destroy method inside of our impersonation controller. And let's go ahead and create this down here. Now, you've probably guessed already how simple this is going to be. All it's going to do is go ahead and say session in the session helper forget.
12:44
And we're going to forget the impersonate. And therefore, the middleware that we've created won't go ahead and pick anything up. So let's just go ahead and return and redirect back to home. Of course, you can include some kind of message in here if you want to.
12:57
Same for this one as well. But we're keeping things nice and simple. OK. So now that we've done this, when we click on this, so on click, pretty much just going
13:06
to do the same thing as the logout process. We go ahead and prevent the default behavior of this. We go ahead and look this up by its ID. So document get element by ID.
13:16
That is, of course, impersonating. And we're going to go ahead and submit that form because, of course, we can't submit this directly with a link inside of it. OK.
13:26
So that should be just about it. Let's just come over and click on this. In fact, it looks a little bit odd. So let's go ahead and make sure this is hidden.
13:35
So let's give this a class of hidden. There we go. Let's go and click on stop impersonating. And it looks like this has just gone through to here.
13:42
Of course, that is because we don't have a post method inside of there. OK. So let's go back to the homepage just to double check this. And I'm going to click stop impersonating.
13:51
And sure enough, that session ID has been removed. And, of course, now the middleware, now that we don't have that impersonate key in the session, is not going ahead and logging us in. Now that is pretty much it, to be honest, how simple it is to impersonate users really
14:08
nice way of doing things just so we can kind of exit out of this session if we need to rather than, like I said at the start of the course, using login using ID. Instead, we're going ahead and logging in just once so we don't override the session and force the admin to log out when they need to stop impersonating.
1 episode 14 mins

Overview

Allowing admins to sign in as other users is simple, but let's look at a more flexible and UX friendly solution.

Alex Garrett-Smith
Alex Garrett-Smith
Hey, I'm the founder of Codecourse!

Episode discussion

No comments, yet. Be the first!