So i have a laravel project with multiple role's (admin, partner, dealer) as a dealer and partner i can download files that are assigned to me using a pivot table.
as a partner i can see 1 file that is assigned to my role to be able to be downloaded. but in my database i have multiple files that a dealer can download. but i am also able to download all the files as a partner if i edit the link: http://localhost:8000/partner/download/{file id i want to download}.
i want to secure this so i can only download files that are assigned to that specific role.
table file:
- Id
- name
- language
- file(downloadable)
table user:
- Id
- name
- role_id
table role;
- id
- name
table download (pivot of file and user):
- id
- file_id
- user_id
controller for the download:
public function download(Request $request, int $fileId)
{
$id = Auth::user();
$fullfile = File::find($fileId);
$downloadfile = File::find($fullfile, ['file'])->pluck('file')->last();
return response()->download($downloadfile);
$fullfile->userfile()->attach($id);
return back();
}
web.php
Route::group(['middleware' => 'role:partner', 'prefix' => 'partner', 'as' => 'partner.'], function(){
Route::resource('/dashboard', App\Http\Controllers\partner\PartnerController::class);
Route::resource('/profile', App\Http\Controllers\partner\ProfileController::class);
Route::resource('/file', App\Http\Controllers\partner\FileController::class);
Route::get('/download/{fileId}',[FileController::class, 'download'])->name('file.download');
});
index.blade.php
<tbody>
@foreach($files as $file)
<tr>
<td>{{$file->title}} </td>
<td>
<a style="background: orange;" href="{{ route('partner.file.show', $file->id) }}">View</a>
</td>
<td>
<a style="background: green;" href="{{ route('partner.file.download', $file->id) }}" >Download</a>
</td>
<td>{{@$file->language->name}} </td>
@foreach($file->tag as $tags)
<td style="background:{{$tags['color']}} ;">{{@$tags->name}} </td>
@endforeach
</tr>
@endforeach
</tbody>
```
CodePudding user response:
I assume you have these tables with relations:
Users, Roles, Files
Users : Roles - N:1 Roles : Files - M:N (that is if your files are either polymorphic or you want certain files to be downloaded by more than 1 role, if neither, then 1:N should suffice)
If not, please provide the schema you have for them.
However if you have schema like this, then it should be relatively easy, you just need to use middleware for the route http://localhost:8000/partner/download/{file id}
that will filter out user by role and return 404 if not accessible
If the route you provided is a path to file located in /public directory (meaning you store the files in /public/partner/download) I suggest creating a hash for each file in the database (something like Str::random(16) ) and use the route http://localhost:8000/partner/download/{hash}
CodePudding user response:
How about using Policy
class FilePolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can view any models.
*
* @param \App\Models\User $user
* @return \Illuminate\Auth\Access\Response|bool
*/
public function view(User $user, File $file)
{
return $user->role_id == 'Partner';
}
}
Then in controller just add
public function download(Request $request, int $fileId)
{
$fullfile = File::find($fileId);
$this->authorize('view',$fullFile);
$id = Auth::user();
$downloadfile = File::find($fullfile, ['file'])->pluck('file')->last();
return response()->download($downloadfile);
$fullfile->userfile()->attach($id);
return back();
}