Reputation: 151
I am new to Firebase so please be gentle. I am making a web app where people can store images on their profile. Images go to Cloud Storage via as described in upload-files#full_example. After they are uploaded I save the downloadUrl in my real-time db. Users have to authenticate via firebase.
login(username: string, password: string): any {
this.httpStatus.setHttpStatus(true);
return this.firebase
.auth()
.signInWithEmailAndPassword(username, password)
.then((firebaseUser: firebase.auth.UserCredential) => {
this.httpStatus.setHttpStatus(false);
this.userService.setUser(firebaseUser);
if (!this.userService.getUser().emailVerified) {
this.userService.getUser().sendEmailVerification();
}
this.router.navigate(['/profile']);
});
}
This is how I upload from client side:
uploadFile() {
this.httpStatus.setHttpStatus(true);
const file = this.file.nativeElement.files[0];
const uid = this.userService.getUser().uid;
const firebase = this.firebaseService.firebase;
const storageRef = firebase.storage().ref();
// Create the file metadata
const metadata = {
contentType: file.type
};
console.log(file);
// Upload file and metadata to the object 'images/mountains.jpg'
const uploadTask = storageRef
.child('userFiles' + '/' + uid + '/' + file.name)
.put(file, metadata);
// Listen for state changes, errors, and completion of the upload.
uploadTask.on(
firebase.storage.TaskEvent.STATE_CHANGED, // or 'state_changed'
function(snapshot) {
// Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded
const progress =
(snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log('Upload is ' + progress + '% done');
switch (snapshot.state) {
case firebase.storage.TaskState.PAUSED: // or 'paused'
console.log('Upload is paused');
break;
case firebase.storage.TaskState.RUNNING: // or 'running'
console.log('Upload is running');
break;
}
},
function(error) {
this.httpStatus.setHttpStatus(false);
this.error.emit(error);
},
() => {
// Upload completed successfully, now we can get the download URL
uploadTask.snapshot.ref.getDownloadURL().then(downloadURL => {
this.httpStatus.setHttpStatus(false);
this.success.emit({url: downloadURL, name: file.name});
});
}
);
}
This is how I save that URL in my DB:
async setDocument(req, callback, errorCallback) {
const url = req.body.url;
const user = req.body.user;
const fileName = req.body.name;
try {
await this.verify(req.body.token);
const result = await this.db
.collection('users')
.doc(user.uid)
.collection('docs')
.doc(fileName)
.set({
url,
fileName
});
callback(result);
} catch (error) {
errorCallback(error);
}
}
This is how I return these URLs:
async getDocuments(req, callback, errorCallback) {
const url = req.body.url;
const user = req.body.user;
try {
await this.verifySameUIDOrAccesslevel(
req.body.token,
req.body.user.uid,
5
);
const result = await this.db
.collection('users')
.doc(user.uid)
.collection('docs')
.get();
const data = [];
result.forEach(each => data.push(each.data()));
callback(data);
} catch (error) {
console.log(error);
errorCallback(error);
}
}
This is how the response to the client looks like:
[{"url":"https://firebasestorage.googleapis.com/v0/b/{{projectId}}.appspot.com/o/userFiles%2FIZxlZnKhQzYEonZf5F6SpMvu1af1%2FNelson_Neves_picuture.gif?alt=media&token=27cce93f-41a3-460b-84e9-4e8b8ceafc41","fileName":"Nelson_Neves_picuture.gif"}]
On the profile i have an anchor tag with this URL as src. Which resolves to:
{
"error": {
"code": 403,
"message": "Permission denied. Could not perform this operation"
}
}
I know this has something to do with the "token=222adabc-2bc4-4b07-b57f-60cbf2aa204c" and I just don't understand why some files can be read and others can't.
My rules for storage are simply:
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if auth != null;
}
}
}
Can someone please explain this token to me and how I can share a permanent URL with my Authenticated users?
Cheers
Upvotes: 1
Views: 1866
Reputation: 1759
Problem is with how you are calling download Url. You have to use same file ref url instead of uploadTask ref.
this.imageFile.name.substr(this.imageFile.name.lastIndexOf('.'));
const fileRef = this.storage.ref(this.filePath); <--- here
this.task = this.storage.upload(this.filePath, this.imageFile);
this.uploadPercent = this.task.percentageChanges();
this.task
.snapshotChanges()
.pipe(
finalize(() => {
this.downloadURL = fileRef.getDownloadURL(); <--- here
this.downloadURL.subscribe(url => {
this.imageUrl = url;
});
})
)
.subscribe();
return this.uploadPercent;
}
Upvotes: 1