28

我已经安装了 Laravel 5.0 并进行了身份验证。一切正常。

我的网站只对经过身份验证的会员开放。内部内容仅对经过身份验证的成员提供保护,但站点内部的图像不受保护以供公众查看。

任何人直接写入图片 URL 都可以看到图片,即使该人没有登录系统。

http://www.somedomainname.net/images/users/userImage.jpg

我的问题:是否可以保护图像(上面的 URL 示例)不被公众查看,换句话说,如果图像的 URL 发送给任何人,个人必须是会员并登录才能看到图像。

这可能吗?怎么做?

4

5 回答 5

35

可以保护 Laravel 5.x 文件夹中的图像不被公开查看

  • 在 Laravel 中的images文件夹下创建文件storage夹(我选择storage了文件夹,因为它已经具有写入权限,当我将图像上传到它时我可以使用它storage/app/images) 。

  • 将要保护的图像从公用文件夹移动到新创建的images文件夹。您也可以选择其他位置来创建images文件夹,但不在公用文件夹内,而是在 Laravel 文件夹结构中,但仍然是不在控制器文件夹内的逻辑位置示例。接下来,您需要创建一个路由和图像控制器。

创建路线

Route::get('images/users/{user_id}/{slug}', [
     'as'         => 'images.show',
     'uses'       => 'ImagesController@show',
     'middleware' => 'auth',
]);

如果人员未登录,该路由会将所有图像请求访问转发到身份验证页面。

创建图像控制器

class ImagesController extends Controller {

    public function show($user_id, $slug)
    {
        $storagePath = storage_path('app/images/users/' . $user_id . '/' . $slug);
        return Image::make($storagePath)->response();
    }
}


编辑(注)

对于那些使用 Laravel 5.2 和更新版本的人。Laravel 引入了新的更好的方式来提供开销更少的文件(这种方式不会重新生成答案中提到的文件):

文件响应

file 方法可用于直接在用户的浏览器中显示文件,例如图像或 PDF,而不是启动下载。这个方法接受文件的路径作为它的第一个参数和一个头数组作为它的第二个参数:

return response()->file($pathToFile);

return response()->file($pathToFile, $headers);

您可以根据需要修改存储路径和文件/文件夹结构,这只是为了演示我是如何做到的以及它是如何工作的。

您还可以添加条件以仅显示控制器中特定成员的图像。

此外,还可以使用文件名、时间戳和其他变量对文件名进行哈希处理。


另外:有人问这种方法是否可以用作公用文件夹上传的替代方法,可以,但不推荐使用此答案中解释的做法。因此,即使您不打算保护它们,也可以使用相同的方法上传存储路径中的图像,只需遵循相同的过程但删除'middleware' => 'auth',. 这样您就不会在公用文件夹中授予 777 权限,并且仍然拥有安全的上传环境。同样提到的答案还解释了如何在没有身份验证的情况下使用此方法,以防有人使用它或提供替代解决方案。

于 2015-06-06T11:46:05.697 回答
12

在以前的项目中,我通过执行以下操作来保护上传:

创建的存储磁盘

config/filesystems.php
'myDisk' => [
        'driver' => 'local',
        'root' => storage_path('app/uploads'),
        'url' => env('APP_URL') . '/storage',
        'visibility' => 'private',
    ],

这将上传\storage\app\uploads\不可供公众查看的文件。

要在控制器上保存文件:

Storage::disk('myDisk')->put('/ANY FOLDER NAME/' . $file, $data);

为了让用户查看文件并保护上传内容免受未经授权的访问。首先检查文件是否存在于磁盘上:

public function returnFile($file)
{
    //This method will look for the file and get it from drive
    $path = storage_path('app/uploads/ANY FOLDER NAME/' . $file);
    try {
        $file = File::get($path);
        $type = File::mimeType($path);
        $response = Response::make($file, 200);
        $response->header("Content-Type", $type);
        return $response;
    } catch (FileNotFoundException $exception) {
        abort(404);
    }
}

如果用户具有正确的访问权限,则提供文件

 public function licenceFileShow($file)
{
    /**
     *Make sure the @param $file has a dot
     * Then check if the user has Admin Role. If true serve else
     */
    if (strpos($file, '.') !== false) {
        if (Auth::user()->hasAnyRole(['Admin'])) {
            /** Serve the file for the Admin*/
            return $this->returnFile($file);
        } else {
            /**Logic to check if the request is from file owner**/
            return $this->returnFile($file);
        }
    } else {
//Invalid file name given
        return redirect()->route('home');
    }
}

最后在Web.php路线上:

Route::get('uploads/user-files/{filename}', 'MiscController@licenceFileShow');
于 2019-07-07T19:18:28.123 回答
3

我实际上并没有尝试过,但我发现 Nginxauth_request模块允许您检查来自 Laravel 的身份验证,但仍然使用 Nginx 发送文件。

它向给定的 url 发送一个内部请求,并检查 http 代码是否成功(2xx)或失败(4xx),成功后,让用户下载文件。

编辑:另一种选择是我尝试过的,它似乎工作正常。您可以使用 X-Accel-Redirect-header 从 Nginx 提供文件。请求通过 PHP,但不是通过发送整个文件,它只是将文件位置发送到 Nginx,然后将其提供给客户端。

于 2016-09-07T19:50:58.600 回答
0

如果我理解你,就像!

 Route::post('/download/{id}', function(Request $request , $id){
  {

     if(\Auth::user()->id == $id) {
         return \Storage::download($request->f);
     } 
     else {
         \Session::flash('error' , 'Access  deny');
         return back();
     }
  }

 })->name('download')->middleware('auth:owner,admin,web');
于 2019-11-11T19:07:14.537 回答
0

公共文件夹中的每个文件都可以在浏览器中访问。如果他们找到文件名和存储路径,任何人都可以轻松获取该文件。

所以更好的选择是将文件存储在公用文件夹之外,例如:/storage/app/private

现在执行以下步骤:

  1. 创建一个路由(例如:private/{file_name})

    Route::get('/private/{file_name}', [App\Http\Controllers\FileController::class, 'view'])->middleware(['auth'])->name('view.file' );

  2. 在控制器中创建一个返回文件路径的函数。创建控制器运行命令php artisan make:controller FileController

并将视图函数粘贴到 FileController

public function view($file)
    {
        $filePath = "notes/{$file}";
        
        if(Storage::exists($filePath)){
            return Storage::response($filePath);
        }
        abort(404);
    }

然后,粘贴use Illuminate\Support\Facades\Storage;到 FileController for Storage

  1. 并且不要忘记根据您的要求分配中间件(在路由或控制器中)(例如:auth)

现在,只有那些有权访问该中间件的人才能通过名为的路由名称访问该文件view.file

于 2022-02-17T07:03:23.380 回答