protecting files by generating links with limited life cycle using Spatie URL-Signer

225 Views Asked by At

I am developing my project using Laravel (ocotber CMS) and using Spatie URL Signer package to protect my files with limited life links. I upload my file to a protected directory blacklisted by .htaccess file.

my .htaccess: RewriteRule ^storage/app/uploads/protected/.* index.php [L,NC]

my file is uploaded to: /storage/app/uploads/protected/58b/d45/789/58bd457897aab778152349.pdf

code that generates the link with expiry date: UrlSigner::sign('http://localhost:8888/storage/app/uploads/protected/58b/d45/789/58bd457897aab778152349.pdf');

the generated link looks like: http://localhost:8888/storage/app/uploads/protected/58b/d45/789/58bd457897aab778152349.pdf?expires=1488905432&signature=fd82b06725096b8e6c43221a9616e420

also i added the Route handling code that uses the package's middleware to protect links. Route::get('protected-route', ['middleware' => 'signedurl', function () { return 'Hello secret world!'; }]);

however the generated link is not available for download. I do suspect this is because i have the file in a protected folder. When i try this with a public folder the file is available. but then there will be no protection on my file. because as you can see above the generated link contains the path to my folder.

1

There are 1 best solutions below

0
On

Since you're handling private files, it's usually a better idea to not let the file system handle those things. Instead, let Laravel do it so you can do all the checks you need and you never have to expose the actual file:

Routes:

// set up a route group with your signedurl middleware
Route::group(['middleware' => 'signedurl'], function () {
    // create a new route which references a controller
    // the {path} is the location of the file
    // so your URLs would look something like
    // http://localhost:8888/media/storage/app/uploads/protected/58b/d45/789/58bd457897aab778152349.pdf
    Route::get('media/{path}', 'MediaController@getPrivateFile');
    // you can also do some validation using
    // ->where('path', '.*?');
});

Then in your new controller:

class MediaController extends Controller
{
    public function getPrivateFile(Request $request, $pathToFile)
    {
        // check if file exists
        // if (file_exists) {
        //     # code...
        // }
        return response()->download($pathToFile);
    }
}

This way your files can remain private, you can run your middleware, and you can do any additional checking you need to in the controller.