typescript - Hiển thị iframe động dựa trên truy vấn cơ sở dữ liệu trong angular fire, giá trị không an toàn, domsanitation
Hiện tại tôi đang sử dụng ionic/angular-fire để tạo một ứng dụng đọc hàng ngày sẽ hiển thị động một iframe cho video YT nhúng tùy theo ngày. Mọi thứ hoạt động tốt cho đến khi tôi thử sử dụng ràng buộc dữ liệu trong URL src của iframe thay vì một URL tĩnh thử nghiệm. Tôi nhận được lỗi: Error: NG0904: giá trị không an toàn được sử dụng trong ngữ cảnh URL tài nguyên (xem https://g.co/ng/security#xss)
Tôi đã nghiên cứu trang này và tìm hiểu về DomSanitizer và SafeResourceUrl. Vấn đề của tôi là tôi đang sử dụng một observable để lấy dữ liệu url và tất cả các dữ liệu khác về bài đọc (tiêu đề, mô tả, v.v.) nên tôi không biết cách triển khai chiến lược này. Tất cả các ví dụ ở đây dường như đang làm việc với url tĩnh hoặc sử dụng phương pháp khác (vanilla js so với cách của Angular/TypeScript). Tôi rất kém trong việc chuyển từ vanilla sang Angular vì tôi đến từ nền tảng PHP nhưng thực sự muốn chuyển sang stack FAng.
Tôi đã cố gắng bao gồm tập lệnh cho DomSanitizer theo các đặc tả của Angular và các gợi ý ở đây trên SO, nhưng có lẽ vì observable, không có gì hoạt động và tôi nhận được lỗi cùng các cảnh báo từ IDE.
Đây là những gì tôi đã làm khi cố gắng triển khai URL động vì tôi không thể hiểu cách đưa nó vào trong hàm getReadings (tôi đoán đây hoàn toàn là chiến lược sai nhưng như tôi đã nói tôi đang bối rối): file data-service.ts:
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
import { Injectable } from '@angular/core';
// eslint-disable-next-line max-len
import { Firestore, collection, collectionData, doc, docData, addDoc, deleteDoc, updateDoc, query, orderBy, limit } from '@angular/fire/firestore';
import { Observable } from 'rxjs';
export interface Readings {
id?: string;
orderNo?: number;
parshah?: string;
date?: string;
videoTorah?: string;
torahPortion?: string;
url?: string;
safeUrl?: string;
}
@Injectable({
providedIn: 'root'
})
export class DataService {
url: string;
urlSafe: SafeResourceUrl;
constructor(
private firestore: Firestore,
private domSanitizer: DomSanitizer
) { }
getReadings(): Observable<Readings[]> {
const readingsRef = collection(this.firestore, 'readings');
const q = query(readingsRef, orderBy('orderNo'), limit(3));
return collectionData(q, { idField: 'id' }) as Observable<Readings[]>;
}
getUrl(readings: Readings): SafeResourceUrl {
this.getReadings();
this.url = 'https://www.youtube.com/embed/' + readings.videoTorah;
this.urlSafe = this.domSanitizer.bypassSecurityTrustResourceUrl(this.url);
return this.urlSafe;
}
}
Trong file home.page.ts của tôi, tôi đã thêm dòng này vào constructor của mình:
this.dataService.getReadings().subscribe(res => {
this.readings = res;
this.cd.detectChanges();
});
this.dataService.getUrl();
my home.page.html ban đầu gọi URL như thế này:
<iframe width="560" height="315" [src]="readings.videoTorah" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
bây giờ nó là:
<ion-list>
<ion-item *ngFor="let reading of readings">
<iframe width="560" height="315" src="getUrl()" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<ion-label>
{{ reading.orderNo }} {{ reading.parshah }} {{ reading.torahPortion }}}
</ion-label>
</ion-item>
</ion-list>
nhưng bây giờ tôi chỉ không chắc làm thế nào để thực hiện toàn bộ sau khi src="getUrl()" không hoạt động. Có lẽ tôi hoàn toàn sai hướng bây giờ nhưng đây chỉ là sở thích và tôi chỉ cần một chút hướng dẫn được không? Tôi chỉ biết rằng tôi đang bỏ sót một thứ gì đó rất đơn giản do thiếu kiến thức chính thức về lập trình. Không có khóa học nào trên Udemy của tôi đề cập đến loại việc này, và vâng, tôi đang quay lại học thêm về TypeScript và RxJS vì tôi thường bị mắc kẹt ở những phần này.
Câu trả lời #1
Angular rất kỹ trong cách nó chấp nhận SafeResource. Những cái này sẽ không hoạt động:
<iframe src={{url}}>
<iframe [src]="method()">
Cách duy nhất tôi có thể làm nó hoạt động là liên kết với một thuộc tính chứa SafeResource. Nhưng điều đó quá hạn chế. Tôi muốn sử dụng Angular một cách đúng đắn với Observables và async pipe cũng như cơ chế phát hiện thay đổi OnPush.
Để kích hoạt điều này, tôi đã tạo một pipe an toàn. Nó được sử dụng như sau:
<iframe
*ngIf="iFrameSrc$ | async as url"
[src]="url | safe: scRESOURCE_URL"
></iframe>
*ngIflà cần thiết vì async pipe trả vềT | nullngay cả khi observable nguồn chỉ trả vềT.scRESOURCE_URLchỉ làpublic readonly scRESOURCE_URL=SecurityContext.RESOURCE_URLtrong lớp component vì Angular không cho phép truy cập các thứ được định nghĩa bên ngoài component.
Triển khai ống
@Pipe({
name: 'safe',
pure: true,
})
export class SafePipe implements PipeTransform {
constructor(private readonly sanitizer: DomSanitizer) {}
public transform(value: string, type: SecurityContext.HTML): SafeHtml;
public transform(value: string, type: SecurityContext.STYLE): SafeStyle;
public transform(value: string, type: SecurityContext.SCRIPT): SafeScript;
public transform(value: string, type: SecurityContext.URL): SafeUrl;
public transform(
value: string,
type: SecurityContext.RESOURCE_URL
): SafeResourceUrl;
public transform(
input: string,
type: SecurityContext
): SafeHtml | SafeStyle | SafeScript | SafeUrl | SafeResourceUrl {
switch (type) {
case SecurityContext.HTML:
return this.sanitizer.bypassSecurityTrustHtml(input);
case SecurityContext.STYLE:
return this.sanitizer.bypassSecurityTrustStyle(input);
case SecurityContext.SCRIPT:
return this.sanitizer.bypassSecurityTrustScript(input);
case SecurityContext.URL:
return this.sanitizer.bypassSecurityTrustUrl(input);
case SecurityContext.RESOURCE_URL:
return this.sanitizer.bypassSecurityTrustResourceUrl(input);
}
throw 'Invalid SecurityContext';
}
}
