If you didn’t noticed some weeks earlier, I wrote a piece praising Laravel Signed Routes and stated why you should use them for everything, even to feed your dog or fill that hole in the road. Few moments after publication, I decided to delete it for one reason: while it worked, the URL could be consumed as many times the user wanted, as long it didn’t expire, which put the burden of blocking subsequent requests in the controller itself.
Tokens, by the other hand, gives you the possibility to consume them. For example, once the user has successfully changed its password, we will delete the token, and the user won’t be able to use the same URL to change his password, since the token won’t exist anymore.
The downside of using tokens is that you need to save it somewhere reliable, like a database. I wanted to avoid that kind of thing, so I resorted to extending the
ValidateSignature middleware with my own way to make Signed Routes consumable.
The secret sauce is some “Cache”
It works this way:
- Checks if the signature exists in the cache. If it is, the signature was consumed and it should denegate the access like when it receives an invalid signature.
- Proceeds to execute the Request in your Controller.
- Before returning the Response, it will put the signature in the cache as long its successful (HTTP code 2××).
- The cache key is set to live until the signature expiration, so when the key expires, the signed route will also expire. Win-win scenario.
That’s pretty much it. Obviously you can expand this with a custom store, like Redis, with tags and a different database. That’s a good way to avoid flushing all the keys with the signatures cache by accident. You are also free to use a relational database like MySQL if you don’t want to rely on the Cache.
Anyway, we can use this middleware like this:
This way, you can just change the
signed middleware in your
app\Http\Kernel.php middleware list, and nothing in your code or routes changes except for the routes or controllers you want to protect with a consumable signature.
I think it’s a pretty nice way to take out the action checks out of the controller into the middleware itself. May be I’ll make a PR into the Laravel framework.