可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have following folder in my Laravel website.
/storage/Asset/Media
This folder can have info like below
/storage/Asset/Media/1/abc.png
/storage/Asset/Media/2/abc.png
Here 1 or 2 is the folder names.
I have following code to secure the folder so that nobody can access the folder without authentication
Route::group(['middleware' => ['web', 'auth']], function () {
Route::get('/storage/Asset/Media/{ID}/{eded}', array(
'as' => 'Files',
'uses' => 'User\Account\Media\MediaController@DownloadMedia',
));
});
so in this way nobody can access the files until user's session is not expired in a browser.
Issue is in Android, so now nobody can access the files due to Auth Middleware.
Can somebody suggest the approach such that, files can be accessible to download via Token Based Authentication(through Android) and also using Auth Controller(through Website)?
回答1:
You don't need to use any other config in routes.php
, everything will work just fine if You follow this guide:
The easiest solution would be to create column named api_token
is users
table. Then when trying to access resource from android device, just add ?api_token=<token>
to Your URL, where <token>
is a api_token
column in Your users
table.
For example:
domain.com/storage/Asset/Media/1/2?api_token=123hello4secret
System will try to search for user record with api_token == 123hello4secret
, so just put that 123hello4secret
into Your user api_token
field.
If You wonder why You should api_token
as column name, the answer is here: https://github.com/laravel/framework/blob/2a38acf7ee2882d831a3b9a1361a710e70ffa31e/src/Illuminate/Auth/TokenGuard.php#L45 Laravel will try to authorize You using api_token
if it is found in request fields.
Also You can use HTTP headers to authorize with token:
Header example:
Authorization: Bearer 123hello4secret
回答2:
Note that by default 'storage' folder is not accessible anyway - only 'public' folder is publicly accessible. Therefore, you can use any URLs for file download controller.
You need two routes - one for cookie-based authentications (web users) and one for stateless (token) sessions:
// URL can be anything you want
Route::get('downloads/{ID}/{eded}', [
'middleware' => ['web', 'auth'],
'as' => 'Files',
'uses' => 'MediaController@DownloadMedia',
]);
// For API tokens, use 'api' guard of Auth middleware
// URL has to be different, too
Route::get('api/downloads/{ID}/{eded}', [
'middleware' => ['auth:api'],
'as' => 'Files',
'uses' => 'MediaController@DownloadMedia',
]);
You also need to add a token field to your users table. Add a line to your users table migration:
$table->string('api_token', 60)->unique();
Then, you need to generate this token. If you want to use the same token (no expiration or refresh), you could generate it when a new user is being created. You could have this in your User class:
/**
* @return void
*/
public function boot()
{
User::creating(function ($user) {
$user->api_token = str_random(60);
});
}
Otherwise, you could force the token to be refreshed on every login attempt (postLogin in AuthController) or maybe have a separate controller method that exchanges email and password for a token.
回答3:
You will need to wrap a new Route within an auth:api
Middleware
This is very simple using Laravel's API authentication.
回答4:
you can put .htaccess file in /storage/Asset/Media
with code:
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>
RewriteEngine On
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
</IfModule>
you can access files in php but direct link to file will not work.
回答5:
In your users table make a nullable column api_token
Now every time user login via the Api, set this api_token
in db and send this to the Api consumer.
Now on further request the Api consumer will send back the token in request header. So just configure the Authenticate Middleware:
public function handle($request, Closure $next)
{
if(!empty($request->header('Auth-Token'))) {
$api_token = $request->header('Auth-Token');
$user = User::where('api_token', $api_token)->first();
if(is_null($user)) //Unauthorize: write response to return
} elseif ($this->auth->guest()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('/');
}
}
return $next($request);
}