如何在 Laravel 5 中保护图像不被 public 查看?

How to protect image from public view in Laravel 5?

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

我的网站只对经过身份验证的会员开放。里面的内容仅对经过身份验证的成员保护,但网站内的图像不受 public 查看保护。

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

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

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

这可能吗?如何实现?

可以保护 public 查看 在 Laravel 5.x 文件夹中的图像。

  • storage文件夹下创建images文件夹(我选择了storage文件夹,因为它已经有写入权限,我可以在我上传图片到它 ) 在 Laravel 就像 storage/app/images

  • 将要保护的图像从 public 文件夹移动到新创建的 images 文件夹。您还可以选择其他位置来创建 images 文件夹,但不在 public 文件夹内,但在 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 为 serve files 引入了新的更好的方法,开销更少(这种方法不会像答案中提到的那样重新生成文件):

File Responses

The file method can be used to display a file, such as an image or PDF, directly in the user's browser instead of initiating a download. This method accepts the path to the file as its first argument and an array of headers as its second argument:

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

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

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

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

也可以将文件名加上文件名、时间戳和其他变量进行散列。


补充: 有人问是否可以使用此方法替代 public 文件夹上传,是的,这是可能的,但不建议按照此说明进行操作. So the same method can be also used to upload images in storage path even if you do not intend to protect them, just follow the same process but remove 'middleware' => 'auth',. That way you won't give 777 permission in your public folder and still have a safe uploading environment. The same mentioned 还解释了如何在没有身份验证的情况下使用此方法,以防有人使用它或提供替代解决方案。

我还没有实际尝试过,但我发现 Nginx auth_request 模块允许您从 Laravel 检查身份验证,但仍然使用 Nginx 发送文件。

它向给定 url 发送内部请求并检查 http 代码是成功 (2xx) 还是失败 (4xx),如果成功,则让用户下载文件。

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

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

已创建存储磁盘:

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

这会将文件上传到 \storage\app\uploads\public 无法查看。

要在您的控制器上保存文件:

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');

如果我理解你的话,就像!

 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');

public 文件夹中的每个文件都可以在浏览器中访问。任何人如果知道文件名和存储路径,就可以轻松获得该文件。

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

现在执行以下步骤:

  1. 创建路线(例如:私人/{file_name})

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

  2. 在控制器中创建一个 returns 文件路径的函数。创建控制器 运行 命令 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

的路由名称访问该文件