Playing
20. Refactoring authorisation

Transcript

00:00
In the next couple of episodes we're going to do some refactoring but one of the side effects of test-driven development, which is what we've been practicing in this series, is that we've written the test, we know everything works, but we've not actually bothered to hook the UI up.
00:14
So we've proved that it works but we don't have the functionality in here to actually do it. So clicking edit a book doesn't work at the moment because we haven't hooked it up, but when we do it'll work. So let's go ahead and make some changes here and we're going to come over to the book's edit page here and just hook this form up to make this
00:33
work. So we know that we want to go through to, now that we've written our test, book slash and then the book id. So let's output the book id in here and we've got a post method here but what we're after is a put method. We can use Laravel's helper here method and just say put and that will go ahead and simulate a put request through to this endpoint. Okay let's go over and check it
00:56
out, edit book and there we go it's been edited. We can't see anything because we didn't change anything but let's say book one updated. Let's say author one updated and there we go. We can see it works and we can change the status of this. Let's change it to reading and there it is under reading now. Okay so at the moment our tests are all passing but what we're going to do is
01:20
refactor the authorization and by that I mean over in the book edit test we checked that it fails if the user doesn't own the book and it should throw a 403. Now if we come over to book edit controller this is what we're doing at the moment but let's change this over to use a policy instead. Remember we're still going to need to access this in the context of a user so we can
01:47
get that pivot information but we can clear up this if statement without having to abort manually with a 403. So let's go ahead and create a policy so php artisan make policy and we're going to call this book policy. Let's open that policy up and let's come down here get rid of the constructor because we're not going to need that and let's define out an action here that we can take on a
02:15
book and this is going to be update. This will apply to both the view here and the actual process of updating the book as well. So into this we're going to get potentially a user and a book and basically we want to check can this user update this book. Let's pull the namespace in for book first of all and this check is basically just going to be that the user's book relationship contains
02:44
this book. So this returns a collection of the books that the user owns and contains we'll just check that this is within it. Now we need to register this policy over in auth service provider so let's come down here we've got an example policy in here we want to hook this book model up to this book policy and then we can just start using this over in our controller. Let's just make
03:09
sure that both of these are pulled in and we should be good to refactor. So let's come over to our controller here and we're going to say this authorize we're going to pass in the action which is update that's the method that we defined and we're going to say book. Now the user is implicit here so the user will be passed in to our book policy and of course this check will return
03:35
true or false. Now what we can do is get rid of this check here and we can just relook the book up so let's just grab this entire line here put that there and then that just hands this check off to a policy which makes more sense. So let's rerun our tests and there we go it still passes that was a successful refactor. Now we can do the same thing now over in our book put controller
04:01
and we can do this right at the top here and we can get rid of this. Now we don't need this book in the context of a user it's not required for this and it's not required for this because we update this pivot in the context of a user anyway so we can actually get rid of this entire chunk of code now to simplify things down. So let's go ahead and run our tests again and sure enough that
04:24
passes. Now because we've got a policy here before we validate it really depends on what you want to do. What you could do is always authorize before you validate that kind of makes sense because there's no point throwing back validation errors if the user doesn't own the book. So we can actually simplify our test down now if we come over to our book put test when we look at this test
04:50
here we don't actually need to pass this data down now because at the point that we hit this the authorization will kick in before the validation so we can actually get rid of all of that now and if we run our test it's still going to pass. So there we go moving over our authorization and we know that we've got our test to back up whether it works they're still passing.

Episode summary

In this episode, we're diving into some refactoring work, especially around how we handle authorization. Up to now, we've been focusing on making sure our code does what we expect, mainly by writing tests first (test-driven development style), but our UI hasn't quite caught up yet. So, we start by actually hooking up the "Edit Book" feature in the UI, making sure the form submits a "PUT" request correctly. After making some updates, we check that everything is working as expected in the browser.

Once we're happy with that, we take a look at the authorization logic. Originally, we had some pretty manual checks in our controllers to make sure a user could only edit their own books. Instead of keeping this logic inline, we clean things up by moving it into a dedicated "policy." By creating a new BookPolicy, we centralize and simplify who can update what.

We then update the AuthServiceProvider to register this new policy, and switch our controllers over to use the new authorize method. This all allows our controllers to be much cleaner. We check our work by running the tests, and they all still pass—a good sign that our changes didn't break anything!

As a nice bonus, switching to policies also gives us the chance to simplify our tests (and code) even further, since authorization is automatically handled before validation now. All in all, this refactor makes our app code more organized, readable, and secure, while maintaining confidence in how everything works through passing tests.

Episode discussion

No comments, yet. Be the first!