Problem: Unpublished Access1:00
Now this is a Book listing maintained by Alice, so it's a Book that hasn't been published, and it's a Book that Stephen, the current user that we're logged in as, shouldn't have permission to see because it's unpublished. So what's going on here is that the route isn't recognizing the unpublished state of the book, and it's just allowing us to view it. We can easily prevent that from happening, so let's jump over into our BookPolicy, and we'll add an extra line in there, and we will block the loading of this page, and we'll use this as a demo for how we use our signed routes. So we'll jump to the code now. Okay, so we're in our BookPolicy, and here is our view method, which is the method that
Update BookPolicy View1:28
So we'll jump to the code now. Okay, so we're in our BookPolicy, and here is our view method, which is the method that is checking the permissions that we have to actually view the book. Now what we want to do here is add in our publish check. So rather than just doing a response allow by default, I'm going to do this, book->published(), and then we're going to do that on there, and then if the book hasn't been published, then we want to fall back to the permissions for the update. So can the user update the book, because if they can, then they have the permissions to view it if it's unpublished. So I'm just going to do this here, update user->book, like so.
view it if it's unpublished. So I'm just going to do this here, update user, book, like so. And what this is going to do is, as I said before, when it hits this policy route, when it hits this method, it's going to check if the book is published. If the book has been published, it's going to allow it, because all published books can be viewed. If the book hasn't been published, it's going to pass it into the update method, which down here is going to go book user is user, allow it, otherwise deny is not found, and we'll jump over to the web browser and we'll check what happens. Okay, so in the browser, here's the page, I'm going to refresh it, and now we have a
Add Preview Route3:25
the preview on this page. So we'll go into the updateBook page, and what we want to do is add a link over here, which will go to a dedicated preview page, and then we can share the link from that dedicated preview page with other people, so they can preview the book, the unpublished book. So we'll jump over to the code, and I'll show you how that's going to work. Okay, first up, I have a quick route here for the previewing the books, this is just the books.preview route, which is pointing to a new controller. So in here we have the PreviewBookController, which has a single method __invoke, which is loading the books.show page, and is pulling in the book on that, when the preview link is accessed.
Generate Signed Preview Link3:58
is loading the books.show page, and is pulling in the book on that, when the preview link is accessed. Okay, so this is the edit blade template for editing the book, maintaining the book, and we're going to add this in here, which says that if the book is not published, then we want to use a signed route, and I'll just scroll over a bit so you can see it better. Okay, so what I've got here, and the important bit, is in this block in here. So this is the bit that generates the signed route, so what we're saying here is, using a URL facade, calling a signedRoute method, and then I've got in here the route name, this is the named route, the name that we put in the routes file, and we're passing in the parameters for the URL.
this is the named route, the name that we put in the routes file, and we're passing in the parameters for the URL. And it would be no different from generating a normal route, except we're adding in a signed route in there. So I'm going to save this, and then go to the page, and we're going to look at the route that it generates. Okay, so we're back on the way of the kings, and I'll refresh the page, and we now have preview unpublished book link down here. So if we see, if we hover over it at the bottom, we can see we now have that cylinder attribute, so the cylinder query string at the end, and if I click on it, we're going to go to the
So if we see, if we hover over it at the bottom, we can see we now have that cylinder attribute, so the cylinder query string at the end, and if I click on it, we're going to go to the preview page. And if we look at the URL of the browser, again we can see the different components we had before. We've got the domain name, and the books, the way of kings, that's the standard route, but then we added in the preview, which is part of the new route we created, and we also have the cylinder here. And what the cylinder is doing, is it's telling the application that the route we're going to is signed, cryptographically signed.
Enforce Signed Middleware6:19
We've just got a preview link that's just the same as the other link before, we can still change the slug in the URL. So we'll jump over to our routes file, and then we'll add in the middleware we need, which will make this work. Okay, so we're in our routes file now, and hopefully some of you picked this up the first time through, is that we have our new route for our preview, but we're not checking for a signed route, for a legitimately signed route. Which means that this is going to respond to every request that hits it. Instead what we want to do is add in the middleware, so I'm going middleware here, signed. And that's all we need to do.
Instead what we want to do is add in the middleware, so I'm going middleware here, signed. And that's all we need to do. This tells Laravel to use the signed route middleware, which will check the URL to see if it has the cylinder in it. And if the cylinder doesn't exist, or if the cylinder doesn't match, then it will reject the request. So let's see it in action. Save this, and we'll go back to our page. Okay, back on the preview page, and I'm going to refresh it without changing the URL. This is the URL where we remove the cylinder, and we should see a difference this time.
request object, you don't have to do it through middleware, so there are multiple ways to do it as well. We're just using the middleware here because it's simpler. And so this is the part, one of the parts you need is the middleware, or you need to verify the cylinder, and that's just a single line. And this is the other piece of our puzzle, where we generate the signed routes. All we have to do, as we looked at before, was the URL::signedRoute method, and then we pass in the route name and the parameters, and it's going to generate us our signed route, our cryptographically secure route, which cannot be tampered with. And this is absolutely fantastic for generating routes that cannot be changed.
Temporary Signed Routes9:45
to guess, and so someone cannot guess the valid cylinder to match the URL they're trying to guess. So it secures all the different things around the URL, so you can safely use URLs for actions and loading pages and sensitive things without risk of the URL being compromised, essentially. But what if you only want the URL to last for a certain amount of time? What if, rather than have it last forever, you say you only want, you know, 15 minutes or an hour or 24 hours or something like that? And we can do that really easily using a temporarySignedRoute method. So we have to do there is add temporary here, temporarySignedRoute, and then we want to add an expiry in here, which tells it how long we want the URL to last for.
So we have to do there is add temporary here, temporarySignedRoute, and then we want to add an expiry in here, which tells it how long we want the URL to last for. Now in the interest of this demo, I'm going to set it to one minute. Now add minute. And what that's going to do is generate a, when the page loads, it will generate a new signed route that will last for exactly one minute. And we will look at the route and I'll show you how it works, and then after a minute, it's going to stop working, and that will show you the expiry of the URL. Okay, so we're on our edit page again and we have our preview unpublished book link. If I refresh the page and then go to that, we can see the page loads and we have a new
Okay, so we're on our edit page again and we have our preview unpublished book link. If I refresh the page and then go to that, we can see the page loads and we have a new addition into the URL up here. We have the expired query parameter. And this has the timestamp at the end of when the page expires. Now the brilliant thing about how signed routes work is that the signature includes all of the query parameters by default, including the expiring time. So you could change the expiry time to say 58 instead of 57 and it's going to break because the signature no longer matches the URL because the expiry time has changed, so a value in the URL has changed.
