Ionic 如何上传图像作为一个签名的请求与云/Angular (5)和离子(3)?

x8goxv8g  于 2022-12-08  发布在  Ionic
关注(0)|答案(2)|浏览(166)

Cloudinary have a basic.js example which I'm trying to implement in my Ionic/Angular project.
Problem is, for some reason the Ionic version of "@cloudinary/angular-5.x" always uses the unsigned_upload feature, and I want to be able to transform it before I upload, same as the Cloudinary example.
Transformation requires signed upload not unsigned upload.
Since there are many versions out-there, and most of the examples don't work, mine is:

Ionic: 3
Angular: 5.2.11

Cloudinary: 
"cloudinary": "^1.11.0",
"cloudinary-core": "^2.5.0",
"@cloudinary/angular-5.x": "^1.0.2"

basic.js

My configuration is inside the .env variable with the structure mentioned in cloudinary.config

var dotenv = require('dotenv');
dotenv.load();

var fs = require('fs');
var cloudinary = require('cloudinary').v2;

// set your env variable CLOUDINARY_URL or set the following configuration
/*cloudinary.config({
  cloud_name: '',
  api_key: '',
  api_secret: ''
});*/

var url = "http://res.cloudinary.com/demo/image/upload/couple.jpg"
cloudinary.uploader.upload(url,{"tags":"basic_sample","width":500,"height":500,"crop":"fit","effect":"saturation:-70"} ,
  function(err,image){
   if (err){ 
    console.warn(err);
    return;
   }

   console.log("* "+image.public_id);
   console.log("* "+image.url);

   // Transform image
   cloudinary.url(image.public_id, 
    {
      width: 200,
      height: 150,
      crop: "fill",
      gravity: "face",
      radius: 10,
      effect:"sepia",
      format: "jpg"
      }
    ));
  });

I'm able with the following code to upload it unsigned

Ionic unsigned request

ngOnInit(): void {
  const uploaderOptions: FileUploaderOptions = {
    url: 'https://api.cloudinary.com/v1_1/' + this.cloudinary.config().cloud_name + '/upload', 
    autoUpload: false,
    isHTML5: true,
    removeAfterUpload: true,
    headers: [{        
        name: 'X-Requested-With',
        value: 'XMLHttpRequest'
    }]
  };

  this.uploader = new FileUploader(uploaderOptions);

  // Add custom tag for displaying the uploaded photo in the list
  this.uploader.onBuildItemForm = (fileItem: any, form: FormData): any => {
    form.append('upload_preset', this.cloudinary.config().upload_preset);
    form.append('public_id', 'subfolder/' + this.UUID);
    form.append('file', fileItem);

    fileItem.withCredentials = false;
    return { fileItem, form };
  };

}

Ionic signed request

So in order to transform my images, I need to use parameter called eager
form.append('eager', 'c_crop,w_191,h_145,g_face,z_0.7');
But then I get the below error

Upload completed with status code 400
 {
  "message": "Eager parameter is not allowed when using unsigned upload.
Only upload_preset,callback,public_id,folder,tags,context,face_coordinates,custom_coordinates,source upload parameters are allowed.
    }

When I remove the preset to "tell" it that maybe this is a signed request, I get the above error + Upload preset must be specified when using unsigned upload
So I'm not sure how I'm suppose to "tell" it - use signed request, and take my configuration from .env or CloudinaryModule.forRoot({Cloudinary}, cloudinaryConfiguration as CloudinaryConfiguration), etc ...

iecba09b

iecba09b1#

For signed upload, you need to create a signature. During post request, you have to attach it with form.
Signature is SHA1 hexadecimal string which is consists of timestamp(unixtime), public_id (any text) and your cloudinary API_SECRET.
Here is my workable sample

private generateSignature() {
    this.public_id = `image_${Date.now()}`; // I like to make it unique.
    this.unixtime = Date.now() / 1000 | 0;
    return CryptoJS.SHA1(`public_id=${this.public_id}&timestamp=${this.unixtime}${this.API_SECRET}`).toString()
}

here I use CryptoJS for encription.
Append this signature with form body before send API request. for example

initFileUploader(): void {
    const self = this;
    self.uploader = new FileUploader({            
        url: 'https://api.cloudinary.com/v1_1/your_cloud_name/upload',
        allowedMimeType: ['image/png', 'image/jpg', 'image/jpeg', 'image/gif'],
        maxFileSize: 524288,//512 KB
        autoUpload: true,
        removeAfterUpload: true,
        isHTML5: true,
        headers: [
            {
                name: 'X-Requested-With',
                value: 'XMLHttpRequest'
            }
        ]
    });
    self.uploader.onAfterAddingFile = (file) => {
        file.withCredentials = false;
    };

    self.uploader.onSuccessItem = (item, response, status) => {
        const resp = <any>JSON.parse(response);
        if (resp) {
            this.onSuccess.emit(resp);
        } else {
            this.onError.emit('An error occured during upload. Please retry');
        }
    };

    self.uploader.setOptions(self._uploaderOptions);

    self.uploader.onBuildItemForm = (fileItem: any, form: FormData): any => {
        let signature = this.generateSignature();

        form.append('timestamp', this.unixtime.toString());
        form.append('public_id', this.public_id);
        form.append('api_key', this.API_KEY); //your cloudinary API_KEY
        form.append('signature', signature);

        return { fileItem, form };
    };                
}

I use ng2-file-upload for uploading...

jtoj6r0c

jtoj6r0c2#

uploading images via signed method
Signed uploads require an authentication signature to be generated on your server using a function method or string method, and as such, signed upload

The current Angular SDK is outdated so we follow these steps to implement our signed upload.

Manually generate Signature via string method in Angular
To manually generate your own POST request, you need to authenticate the request with a signature based on the parameters you use in the request. The signature is a hexadecimal message digest (hash value) created with the SHA-1 or SHA-256 (Secure Hash Algorithm) cryptographic function.

You can manually generate the comparison signature instead of using the Cloudinary SDK’s api_sign_request method.

For example, if your API secret is abcd, your API key is 1234, the Unix time now is 1315060510 and you are posting a request to upload a file from ‘https://www.example.com/sample.jpg', set its Public ID as sample_image, and eagerly generate 2 images:

Parameters to sign:
timestamp: 1315060510
public_id: sample_image
eager: w_400,h_300,c_pad|w_260,h_200,c_crop
Serialized sorted parameters in a single string:
eager=w_400,h_300,c_pad|w_260,h_200,c_crop&public_id=sample_image&timestamp=1315060510
String including the API secret that is used to create the SHA-1 signature:
eager=w_400,h_300,c_pad|w_260,h_200,c_crop&public_id=sample_image&timestamp=1315060510abcd
Generate Signature in Angular
Using a native js function for hashing messages with the SHA-1 algorithm

First Install sha1

npm install sha1

Then import the package into the app

import sha1 from ‘sha1’;

Generate UUID for Public ID
Another thing we did so each upload has a unique ID was to using UUID package to generate a unique Public ID for each upload

npm install uuid

import * as uuid from ‘uuid’;

on NgInit we generate the UUID using

this.uuidValue = `${uuid.v4().toLowerCase()}`;

we the use method sha1(string) Returns the SHA-1 hash of the given message.
The result is a SHA-1 hexadecimal result:

b4ad47fb4e25c7bf5f92a20089f9db59bc302313

  

     signuploadform() {
        const timestamp = Math.round(new Date().getTime() / 1000);
        const apiSecret = this.environmentService.getValue('CLOUDINARY_API_SECRET');
        const api_key = this.environmentService.getValue('CLOUDINARY_API_KEY');
        const signature = sha1(
          'eager=c_pad,h_300,w_400|c_crop,h_200,w_260&folder=identification/NGA&public_id=' +
            this.uuidValue +
            '&timestamp=' +
            timestamp +
            apiSecret
        );
        return {timestamp, signature, api_key};
      }

Post the Upload
Now that the signature has been generated we then post using the parameter as shown in the code below

folder
public_id
file
api_key
timestamp
signature
HTML
<input hidden (change)=”onFileChange($event)” #fileInput accept=”image/*” type=”file” id=”file”>

TS
onFileChange(event: any) {
    this.uploadFile(event.target.files[0]);
  }
    
  uploadFile(file: File) {
    const signData = this.signuploadform();
    const formData = new FormData();
    formData.append('eager', 'c_pad,h_300,w_400|c_crop,h_200,w_260');
    formData.append('folder', 'identification/NGA');
    formData.append('public_id', this.uuidValue);
    formData.append('file', file);
    formData.append('api_key', signData.api_key);
    formData.append('timestamp', signData.timestamp.toString());
    formData.append('signature', signData.signature);
    const url =
      'https://api.cloudinary.com/v1_1/' +
      this.environmentService.getValue('CLOUDINARY_CLOUD_NAME') +
      '/auto/upload';
    this.isLoading = true;
    this.http
      .post(url, formData)
      .pipe(map((x: any) => x.secure_url as string))
      .subscribe({
        next: res => {
          this.identification = res;
          this.uploadTitle = 'ID Uploaded';
          this.uploadStatus = true;
          from(
            Swal.fire({
              icon: 'success',
              title: 'Successfully uploaded',
              showConfirmButton: true,
            })
          );
        },
        error: error => {
          this.isLoading = false;
          from(
            Swal.fire({
              icon: 'error',
              title: 'Please check your image again',
              showConfirmButton: true,
            })
          );
        },
        complete: () => {
          this.isLoading = false;
        },
      });
  }

相关问题