Laravel - Include assets on Middleware Auth - php

Inside my app, exist a route group called admin, any route inside this group call two resources: public/css/admin.css and public/js/admin.js, but any unauthenticated user has access to these files. How can I include these files inside the Auth Middleware?
My admin routes:
Route::group(['prefix' => 'admin', 'middleware' => ['auth']], function () {
Route::get('/', 'Admin\IndexController#index')->name('panel');
Route::group(['prefix' => 'users'], function() {});
Route::group(['prefix' => 'settings'], function() {});
Route::fallback('Admin\ExceptionController#exception');
});
My resources links:
http://localhost:3000/css/admin.css
http://localhost:3000/js/admin.js
My resources links should be:
http://localhost:3000/admin/css/admin.css
http://localhost:3000/admin/js/admin.js
If I just create the folder admin inside the public folder I just got a 403 error...
What can I do about it?

I suppose you are using it because you don't want unauthenticated users to know the contents of these css/js files.
You shouldn't have any sensitive information in your css/js files, so there is no problem on serving them.
Otherwise, if you want to limit access to a file you should make the file download through PHP. For example you could have the file outside you public folder and make it conditional downloadable through a method that gets file contents and serves for download.
You should can make that public admin folder though, check file permissions and file ownership.

Update: Now we'll use storage instead of public directory.
Although I agree that you should not have any sensitive info in your css/js files but if you really want to serve the files to authenticated users you can do it with this work around.
NOTE: I have made the project publicaly avaiable on git so you can clone from there if you want. Git Repo
Create a directory for admin assets with permission 755
Create a helper function to serve admin assets.
Make the helper function available in blade.
Link the assets using the helper function in order to first authenticate and then serve the file.
Basic Idea:
The basic idea is to have a directory which no one can access via
browser.
Authenticate the user
Copy the files from protected directory.
Paste the files in a new directory (in storage) only associated with the authenticated user.
Delete the associated directory on user logout.
Implementation:
Created a directory called admin_assets in public directory.
Change the permission of the directory to 755.
Created a helper class named CommonHelper, and write functions to serve and delete admin assets.
Served the assets with these helper functions as following:
<link href="{{ asset( CommonHelper::serveAdminAssets('app.css', '/css/') ) }}" rel="stylesheet">
Deleted the files at logout.
Finally, as far as the user is logged in the files will be available for him/her, all files will be deleted from the folder once the user logs out.
CommonHelper class:
<?php
/**
*
*/
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
class CommonHelper {
public static function serveAdminAssets($fileName, $filePath) {
if( Auth::check() ) {
$adminAssetsBasePath = public_path().'/admin_assets';
$source = $adminAssetsBasePath.$filePath.$fileName;
$destDir = 'public/'.Auth::user()->id.$filePath;
$dest = $destDir.$fileName;
Storage::put($dest, file_get_contents($source));
return Storage::url($dest);
} else {
return '';
}
}
public static function removeAdminAssets($id) {
$destDir = storage_path('app/public/'.Auth::user()->id);
File::cleanDirectory($destDir);
File::deleteDirectory($destDir);
}
}
?>
Notes:
Remember, if you are using the local driver, all files that should be
publicly accessible should be placed in the storage/app/public
directory. Furthermore, you should create a symbolic link at
public/storage which points to the storage/app/public directory. Docs
Before deleting a directory you should empty it first.

Here is an example that you can apply.
Store your assets in storage directory.
then you can check whether it is an admin or Not.
In your view you can u can inject the Admin Assets Like.
<script>
{!! \Storage::disk('urdisk name')->get('admin.js'); !!}
</script>
for your css you can
<style>
{!! \Storage::disk('urdisk name')->get('admin.css'); !!}
</style>
Hope this helps

For applying auth to the asset files you need to go through from the laravel, not by accessing the files using full path, you need to access css/js files via route so that laravel will be able to apply auth on each files inside route group.
P.S Files must be saved inside storage folder, i-e storage/admin.css
Updated route group
Route::group(['prefix' => 'admin', 'middleware' => ['auth']], function () {
Route::get('/', 'Admin\IndexController#index')->name('panel');
Route::get('{file}', 'StaticFileController#serveFile');
Route::group(['prefix' => 'users'], function() {});
Route::group(['prefix' => 'settings'], function() {});
Route::fallback('Admin\ExceptionController#exception');
});
Controller
namespace App\Http\Controllers;
use Illuminate\Http\Request;
Use Response;
use App\Http\Requests;
class StaticFileController extends Controller
{
public function serveFile ($file)
{
$storagePath = storage_path($file);
$mimeType = mime_content_type($storagePath);
if( ! \File::exists($storagePath)){
return view('errorpages.404');
}
$headers = array(
'Content-Type' => $mimeType,
'Content-Disposition' => 'inline; filename="'.$file.'"'
);
return Response::make(file_get_contents($storagePath), 200, $headers);
}
}
Now your resources links would be
http://localhost:3000/admin/css/admin.css
http://localhost:3000/admin/js/admin.js
Hope this helps

For blade templates you can use the #auth directive.
When you're including these files in your blade templates, you can wrap the script tag in an #auth directive and they'll only be rendered when the user is authenticated.
E.g.
#auth
<script src="{{ asset('path/to/your/js') }}"></script>
#endauth
There's also an optional parameter that allows you to set the guard you want to check for e.g. #auth('your-guard').
It's available in Laravel 5.5+
Here's the documentation for a better overview of its use.

Related

How to access a file from storage in Laravel 5.8

I have a file inside my storage folder.
Located path :
storage/app/public/$/10012940/gallery/289sdas98e.jpg
$, 10012940 and 289sdas98e.jpg is dynamic and can change.
Route::get('storage/{$folderDirectory1}/{$customerReference}/gallery/{file}', function ($filename)
{
});
Since its a nested folder I cannot find much on internet as to what the route should look like. Also how to go about doing something like that.
I am trying to find a way to access this path via the route so that I can write a middleware to authenticate before making this accessible to the end user.
I am storing the file inside the storage folder due to the visibility. I would like to control who should have access to viewing the image
You should use a route name.
For instance, in your view: href="{{ route('assets.show', $asset) }}".
In your AssetController#show, simply return Storage::download($asset) for instance.
Then use your middleware to authorize or not the access to the show method.

Middleware for public storage in Laravel

I have this structure: laravel/storage/app/public/images/id_of_user/
Where id of user is the id of the user.
This is my middleware:
public function handle($request, Closure $next)
{
if($request->user_id == Auth::user()->id{
return $next($request);
}
return back();
}
and made a route like this:
Route::group(['middleware' => 'storagemiddleware'], function () {
Route::get('storage/images/{$user_id});
});
This doesn't work, tho. Everyone can still acess to everyones images. I honestly didn't expect this to work since it seems that storage has its own special routes and settings.
What I want is that only the users are allowed to see the content of their folder in their storage.
Any suggestions?
Read through this section of the documentation: https://laravel.com/docs/5.4/filesystem.
If the idea is to keep files accessible only to those you own them, you'll want to put them somewhere in the storage directory and then access them through a controller. Anything in your public directory is just that, public.
You could setup a directory structure like this storage/user_data/<$user_id>/ to keep things separated, then retrieve them from your route and the specified parameter.

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

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.
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.

Secure Asset/Media Folder through Auth Controller ? Laravel 5.2

I have public/Asset/Media/folder
I can access this file publicly like below.
http://localhost/myapp/public/Asset/Media/1/phpunit.xml
Similarly there are other folders in the Asset/Media folder which are being created on the fly.
There are many files also present in those sub folder and are also present in Asset/Media folder
Is there any way, such that if I try to access any file in Asset/Media folder or any file present in the sub folder of Asset/Media folder, I should be redirected to login page because authentication is not done?
I meant, can i use Auth Middleware to secure this folder? if so, Is it a valid approach if we have to access the files from a Android App?
If you want to secure files, they need to go through Laravel. Accessing the file as you do (using the full path) does not go through Laravel. You can achieve this by creating a route:
Route::group(['middleware' => ['auth']], function () {
Route::get('/secure/file/{file_name}', 'FileController#file');
}
Then, create a Controller to access the file so that you can use Auth to check for permission to access. It also means that you should put the file in an inaccessible location and use the Laravel Filesystem to access the file using PHP:
class FileController extends Controller {
public function file()
{
return Storage::get('path/to/phpunit.xml');
}
}
Laravel 5.2 has introduced HTTP Middleware, i would advise you to do it.
https://laravel.com/docs/5.2/middleware#middleware-groups
this thread might help you to get it to work...
Laravel 5.2 Auth not Working
Use the route below for it:
Route::get('/myapp/public/Asset/Media/{id}', function ($id) {
if (Auth::guest()){
return Redirect::guest('login');
}else{
$img="/myapp/public/Asset/Media/".$id;
if(File::exists($img)) {
return Response::make($img, 200, array('content-type' => 'image/jpg'));
}else{
return false;
}
})->where('id', '.+');
My sample url is here:
http://domainname.com/storage/Asset/Media/1/filename.txt
My route
Route::get('/storage/Asset/Media/{ID}/{file}', array(
'as' => 'Files',
'uses' => 'User\Account\Media\MediaController#DownloadMedia',
));
Controller Action Method
public function DownloadMedia($ID) {
$headers = array(
'Content-Type' => 'application/octet-stream',
'Content-Disposition' => 'attachment; filename=somefile.txt"'
);
return response()->download(base_path("storage/Asset/Media/1/somefile.txt"));
}
Here important thing is I can use application/octet-stream to download any file type.
File in public folder will be accessible to everyone beacause of rewrite rules used by Laravel, Laravel won't even be called when someone access a file in the public folder.
So, you must put your restricted files somewhere else, maybe in storage folder but ultimately it doesn't matter.
After putting all your Asset/Media folder into the storage folder and updating your code who create your folder on the fly (How storage works).
Create a FileController :
PHP
class FileController extends Controller {
public function __construct() {
$this->middleware('auth');
}
public function downloadFile($filename) {
return response()->download(storage_path($filename), null, [], null);
}
}
The configure this route :
Route::get('file/{filename}', 'FileController#downloadFile')->where('filename', '^[^/]+$');
That's it, now only your authenticated user would be able to download asset files thanx to the middleware auth, that will also work for android app.

Laravel link_to_route after namespace change

I was making a basic CRUD app from a tutorial but realised I wanted to mask the feature inside an admin folder.
The feature was a blog management system (index, create, show, delete etc) and this all ran from domain.com/blog.
Since then, I have built a user system and a protected admin area so have decided to move the view files into an admin folder.
To counter this change, I asked on here and was instrcuted to wrap my resource route in this:
Route::group(array('before' => 'is_admin', 'namespace' => 'admin', 'prefix' => 'admin'), function()
Route::resource('blog', 'BlogController');
});
Then move my BlogController into an admin folder in my controller folder, then add a namespace to that controller:
namespace Admin;
and add a backslash before the BaseController.
This line here:
return View::make('admin/blog.index', compact('blogs'));
Was causing errors, so I had to add a backslash before the View::
return \View::make('admin/blog.index', compact('blogs'));
How do I not have to do that for all the classes?
And then once that is okay, my index file contains:
{{ link_to_route('blog.create', 'Add new blog') }}
Which is returning undefined route errors... where am I going wrong? The resource route should be catching these routes etc surely? Seems alot of work to simply make the BlogController work in an admin directory...
This is how namespaces work. You can import namespaces adding:
use View;
and now you will be able to use just View and not \View in other places of your file so the beginning of your file should look like this:
<?php namespace Admin;
use View;
But you will need to add this to each file you moved to namespace Admin;
You could also read How to use objects from other namespaces and how to import namespaces in PHP to understand it a bit better.

Categories