I'm using Strapi with local upload provider.
Whenever I upload a file, it is stored under the "public/uploads" folder locally, which is public.
Meaning that anyone with the file id, could download it eg. http://strapi-admin:1337/uploads/image1_9a9bd50a5b.png
However, I would like to only allow:
downloads to autenticated users which have the role "consumer" to be able to download files through the strapi API.
What is the best way for doing this?
Should I modify the upload extension directly? or is it any workaround I can use to implement this?
I would still like to store files locally (not using AWS3 and other cloud providers)
Thanks
The best way you can solve this is to create a collection e.g FileShare. The Collection table could be like this: uuid (UID), filename (TEXT), fileid (NUMBER), role(related to Roles table), user(relate to user-permission table), status (BOOLEAN).
Using this logic, you will have to create a new route for file upload, the code upload from respective controller, The code below will help:
const validateUploadBody = require('strapi-plugin-upload/controllers/validation/upload');
async create(ctx){
let userData=ctx.state?.user; let requestData=ctx.request.body;
const {
request: { body, files: { files } = {} },
} = ctx;
let uploadedFiles = await strapi.plugins.upload.services.upload.upload({
data: await validateUploadBody(body),
files,
});
let datat={
filename:uploadedFiles[0].name,
fileid:uploadedFiles[0].id,
status:true,
uuid:"3456345678", // Generate random perhaps use moment().format("x")
role:2 //it can be any role of your choice
}
let updateLibrary= await strapi.query('file-shares').create(datat);
}
Ensure to use the uuid as the download enpoint from your frontend e.g https://example.com/file/2343567. Don't expose your media library url.
Then create a controller that will look for the file from FileShare table, check necessary permission for the user then download the file.
Related
I followed the documentation to upload files to my public folder, and now I wish I could delete a file from that folder.
if I use the query provided by api platform: api/image/{id} I can only delete the row in my table. I would already have to retrieve the path of the image to save it in the table. And maybe then I can use it to delete the image?
I need a Deserializer ?
Laurent.
You need to create an EventListener and listen to the postRemove event so that after deleting an entry from the Image entity, you physically remove the file from the directory.
An example of listening for events on an Image entity:
class ImageEventSubscriber
{
public function postRemove(Image $image, LifecycleEventArgs $event){
$image_path = $image->getPath(); // You may have to specify the full path to the file if it is not listed in the database.
if (file_exists($image_path))
{
unlink($image_path);
}
}
}
Now you need to declare your event listener in the services.yaml file
App\EventListener\ImageEventSubscriber:
tags: [ { name: doctrine.orm.entity_listener, entity: App\Entity\Image, event: postRemove } ]
Now, when requesting DELETE: api/image/{id}, the record and file will be deleted. You can get more information about EventSubscriber by reading the documentation.
I'm creating a model that I will use to authenticate users for API access, and I have a secret field where I want to store a Base64 encoded uuid/v4 generated value.
I went through the different field types and options, but still not seeing how I could achieve this.
Is there a way to hook in model instance creation, and set the value of my secret field ?
Yes, you can use the pre hooks.
In your situation, the basics would be:
AuthenticationModel.schema.pre("save", function(next) {
const secretValue = generateSecretValue();
this.secret = secretValue;
next();
});
That would go before your final AuthenticationModel.register(); in your model.js file.
This is how I set it up, also with the pre-save hook. My problem before was that I was getting the same random number again until I restarted the server.
Store.schema.pre('save', function (next) {
if (!this.updateId && this.isNew) {
// generates a random ID when the item is created
this.updateId = Math.random().toString(36).slice(-8);
}
next();
});
Using this.isNew was also useful in my case.
I am using this SDK and following this documentation. Now I am trying to create and authenticate user in firebase db. How can I do that.I am doing the project in Codeigniter and in my controller I did this:
public function register()
{
$firebase = (new Firebase\Factory())->create();
$tokenHandler = $firebase->getTokenHandler();
$uid = 'a-uid';
$claims = ['foo' => 'bar']; // optional
// Returns a Lcobucci\JWT\Token instance
$customToken = $tokenHandler->createCustomToken($uid, $claims);
echo $customToken; // "eyJ0eXAiOiJKV1..."
$idTokenString = 'eyJhbGciOiJSUzI1...';
// Returns a Lcobucci\JWT\Token instance
$idToken = $tokenHandler->verifyIdToken($idTokenString);
$uid = $idToken->getClaim('sub');
echo $uid; // 'a-uid'
}
and I call the function It gave me this error:
Type: Kreait\Firebase\Exception\ServiceAccountDiscoveryFailed
Message: Kreait\Firebase\ServiceAccount\Discovery\FromEnvironmentVariable: The environment variable "FIREBASE_CREDENTIALS" is not set. Kreait\Firebase\ServiceAccount\Discovery\FromEnvironmentVariable: The environment variable "GOOGLE_APPLICATION_CREDENTIALS" is not set. Kreait\Firebase\ServiceAccount\Discovery\FromGoogleWellKnownFile: The well known file is not readable or invalid
Filename: E:\xampp\htdocs\firebasedb\vendor\kreait\firebase-
php\src\Firebase\ServiceAccount\Discoverer.php
Line Number: 48
Can anyone help me with this issue? Any kind of help are appreciated. Thanks.
EDIT
Okay I solve this problem with default .json file path like this:
$serviceAccount = ServiceAccount::fromJsonFile(JSON_FILE_PATH.'google-service-account.json');
$firebase = (new Factory)
->withServiceAccount($serviceAccount)
->create();
Now can I register a new user from web-app? Can anyone Help please. I have been stopped in this problem since long. Helps are highly appreciated.
You Set JSON Key environment variables
FIREBASE_CREDENTIALS GOOGLE_APPLICATION_CREDENTIALS ?
try reading this Firebase Admin SDK for PHP Setup
From the documentation https://firebase-php.readthedocs.io/en/latest/authentication.html#authenticate-with-admin-privileges
There two crucial points to note.
Many use cases for verifying ID tokens on the server can be accomplished by using Security Rules for the Firebase Realtime Database and Cloud Storage. See if those solve your problem before verifying ID tokens yourself.
The ID token verification methods included in the Firebase Admin SDKs are meant to verify ID tokens that come from the client SDKs, not the custom tokens that you create with the Admin SDKs Check out https://firebase.google.com/docs/auth/users/#auth_tokens
About Users:
From https://firebase-php.readthedocs.io/en/latest/user-management.html
You have a sample
$request = \Kreait\Auth\Request\CreateUser::new()
->withUnverifiedEmail('user#example.com')
->withPhoneNumber('+15555550100')
->withClearTextPassword('secretPassword')
->withDisplayName('John Doe')
->withPhotoUrl('http://www.example.com/12345678/photo.png');
$createdUser = $auth->createUser($request);
Please Note:
By default, Firebase Authentication will generate a random uid for the new user. If you instead want to specify your own uid for the new user, you can include in the properties passed to the user creation method:
$properties = [
'uid' => 'some-uid',
// other properties
];
$request = \Kreait\Auth\Request\CreateUser::new()
->withUid('some-uid')
// with other properties
;
I had same problem with Laravel in my case, here is the solution:
First save the .json credentials file you got from Firebase project into the root of your Laravel app on the same level as .env file.
The json file looks like you-file-firebase-adminsdk-0000-9845985498a.json
Then open the .env file and create a new environment variable and paste the json credential file name.
FIREBASE_CREDENTIALS=../you-file-firebase-adminsdk-0000-9845985498a.json
I am trying to access properties located on the User object for the current user in a cloud code function. The current user is passed to the cloud code function and available at request.user. The Cloud Code is deployed to Heroku using parse-cloud-express.
When the request first arrives, it does not contain the user data other than the id.
So I tried performing a fetch to get the latest data:
Parse.Cloud.define("functionName", function (request, response) {
request.user.fetch().then(function (user) {
console.log(util.inspect(user));
});
});
But it outputs the same data and does not seem to include the User object's properties.
2015-12-15T01:19:08.830880+00:00 app[web.1]: { _objCount: 1, className: '_User', id: 'dKqZMSRgDc' }
I also tried performing a query on the user id, but receive the same result.
var userQuery = new Parse.Query(Parse.User);
userQuery.get(request.user.id).then(function (user) {
console.log(util.inspect(user));
});
How do I get the properties of the User object?
The problem was not with getting data for the User object, but the way I was logging it. It seems that the data is not available from the object itself, so the output from util.inspect was correct, but does not include any properties. (I'm guessing the internals of the Parse framework manages this in another way.)
I replaced with console.log(user.toJSON()) and can now see the expected data for the user.
I would like to execute the below line when the user logs in so that I have access to the MembershipUser object. However I am having a hard time figuring out when to set it.
Session["User"] = Membership.GetUser();
So far I've tried...
Application_AcquireRequestState
Application_BeginRequest
FormsAuthentication_OnAuthenticate
For each the session state isn't necessarily available.
Manually calling it in the log-in page is easy, but I need to have it work when automatically logging in using cookies as well.
If all you want do is store arbitrary data along with the username, there is an open source project called FormsAuthenticationExtensions that allows you to do exactly this in a very simple manner:
In your Login action you would store your data like this:
var ticketData = new NameValueCollection
{
{ "name", user.FullName },
{ "emailAddress", user.EmailAddress }
};
new FormsAuthentication().SetAuthCookie(user.UserId, true, ticketData);
And you read it back like this:
var ticketData = ((FormsIdentity) User.Identity).Ticket.GetStructuredUserData();
var name = ticketData["name"];
var emailAddress = ticketData["emailAddress"];
Data is stored in the same cookie holding the authentication ticket, so it will be available for as long as the user is logged in.
Project page: http://formsauthext.codeplex.com/
Nuget: http://nuget.org/List/Packages/FormsAuthenticationExtensions
Why? You can access Membership.GetUser from anywhere. It's a static method. What is the point of placing a value you can access from anywhere in a place you can access from anywhere?