Небезопасное значение, используемое в контексте URL ресурса с Angular 2
После обновления до последней версии-кандидата Angular 2 мои теги img выдают ошибку.
Тег img:
<img class='photo-img' [hidden]="!showPhoto1" src='{{theMediaItem.photoURL1}}'>
Создайте ошибку браузера:
ORIGINAL EXCEPTION: Error: unsafe value used in a resource URL context
Значение URL-адреса:
http://veeu-images.s3.amazonaws.com/media/userphotos/116_1464645173408_cdv_photo_007.jpg
РЕДАКТИРОВАТЬ:
Я попробовал предложение, сделанное в другом решении, что этот вопрос должен быть дубликатом, но я получаю ту же ошибку.
Я добавил следующий код в контроллер:
import {DomSanitizationService} from '@angular/platform-browser';
@Component({
templateUrl: 'build/pages/veeu/veeu.html'
})
export class VeeUPage {
static get parameters() {
return [[NavController], [App], [MenuController], [DomSanitizationService]];
}
constructor(nav, app, menu, sanitizer) {
this.app = app;
this.nav = nav;
this.menu = menu;
this.sanitizer = sanitizer;
this.theMediaItem.photoURL1 = this.sanitizer.bypassSecurityTrustUrl(this.mediaItems[1].url);
}
Я все еще получаю то же сообщение об ошибке.
EDIT2:
Я также изменил HTML на:
<img class='photo-img' [hidden]="!showPhoto1" [src]='theMediaItem.photoURL1'>
Я все еще получаю то же сообщение об ошибке
11 ответов
Я использую RC.4, и этот метод работает для ES2015(ES6):
import {DomSanitizationService} from '@angular/platform-browser';
@Component({
templateUrl: 'build/pages/veeu/veeu.html'
})
export class VeeUPage {
static get parameters() {
return [NavController, App, MenuController, DomSanitizationService];
}
constructor(nav, app, menu, sanitizer) {
this.app = app;
this.nav = nav;
this.menu = menu;
this.sanitizer = sanitizer;
}
photoURL() {
return this.sanitizer.bypassSecurityTrustUrl(this.mediaItems[1].url);
}
}
В HTML:
<iframe [src]='photoURL()' width="640" height="360" frameborder="0"
webkitallowfullscreen mozallowfullscreen allowfullscreen>
</iframe>
Использование функции гарантирует, что значение не изменится после его очистки. Также помните, что используемая вами функция очистки зависит от контекста.
Для изображений bypassSecurityTrustUrl
будет работать, но для других целей вам необходимо обратиться к документации:
https://angular.io/docs/ts/latest/api/platform-browser/index/DomSanitizer-class.html
Способ 1:
import { DomSanitizer } from '@angular/platform-browser';
...
constructor(public sanitizer: DomSanitizer){}
... тогда в HTML:
<iframe [src]='sanitizer.bypassSecurityTrustResourceUrl(myurl)' width="640" height="360" frameborder="0"
webkitallowfullscreen mozallowfullscreen allowfullscreen>
</iframe>
Способ 2:
Сначала я должен был выполнить санацию в коде, потому что Vimeo не будет максимизировать на Edge
Это всего лишь пример, суть в том, что сначала санируйте в коде так, как вам нравится.
Интерфейс объекта:
import { SafeUrl } from '@angular/platform-browser';
export class Book {
constructor(public title: string, public videoURL?: SafeUrl) {}
}
Сервис (как пример):
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import { Book } from '../features/models/book';
import { DomSanitizer } from '@angular/platform-browser';
@Injectable()
export class BookService {
constructor(
private sanitizer: DomSanitizer
) {}
getBooks (): Observable<Book[]> {
return new Observable( observer => {
observer.next(
new Book(
'Some Book Title',
this.sanitizer.bypassSecurityTrustResourceUrl(
'https://player.vimeo.com/video/12345678'
)
),
new Book(
'Second BookTitle',
this.sanitizer.bypassSecurityTrustResourceUrl(
'https://player.vimeo.com/video/91011121'
)
)
)
});
}
}
Самый элегантный способ исправить это: использовать трубу. Вот пример (мой блог). Таким образом, вы можете просто использовать url | safe
труба, чтобы обойти безопасность.
<iframe [src]="url | safe"></iframe>
Используйте Safe Pipe, чтобы исправить это.
Создайте безопасную трубу, если у вас ее нет.
NG GC трубы безопасны
добавить Безопасную трубу в app.module.ts
декларации: [ SafePipe ]
объявить безопасную трубу в тс
Импортируйте Dom Sanitizer и Safe Pipe для безопасного доступа к URL.
import { Pipe, PipeTransform} from '@angular/core';
import { DomSanitizer } from "@angular/platform-browser";
@Pipe({ name: 'safe' })
export class SafePipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) { }
transform(url) {
return this.sanitizer.bypassSecurityTrustResourceUrl(url);
}
}
- Добавить сейф с помощью src url
<iframe width="900" height="500" [src]="link | safe"/>
Либо вы можете предоставить sanitizer представлению, либо предоставить метод, который перенаправляет вызов bypassSecurityTrustUrl
<img class='photo-img' [hidden]="!showPhoto1"
[src]='sanitizer.bypassSecurityTrustUrl(theMediaItem.photoURL1)'>
Angular по умолчанию считает все значения ненадежными. Когда значение вставляется в DOM из шаблона через свойство, атрибут, стиль, привязку класса или интерполяцию, Angular очищает и избегает ненадежных значений.
Поэтому, если вы напрямую манипулируете DOM и вставляете в него контент, вам необходимо очистить его, иначе Angular выйдет из строя.
Я создал канал SanitizeUrlPipe для этого
import { PipeTransform, Pipe } from "@angular/core";
import { DomSanitizer, SafeHtml } from "@angular/platform-browser";
@Pipe({
name: "sanitizeUrl"
})
export class SanitizeUrlPipe implements PipeTransform {
constructor(private _sanitizer: DomSanitizer) { }
transform(v: string): SafeHtml {
return this._sanitizer.bypassSecurityTrustResourceUrl(v);
}
}
и вот как вы можете использовать
<iframe [src]="url | sanitizeUrl" width="100%" height="500px"></iframe>
Если вы хотите добавить HTML, то SanitizeHtmlPipe может помочь
import { PipeTransform, Pipe } from "@angular/core";
import { DomSanitizer, SafeHtml } from "@angular/platform-browser";
@Pipe({
name: "sanitizeHtml"
})
export class SanitizeHtmlPipe implements PipeTransform {
constructor(private _sanitizer: DomSanitizer) { }
transform(v: string): SafeHtml {
return this._sanitizer.bypassSecurityTrustHtml(v);
}
}
Подробнее о безопасности angular читайте здесь.
Я обычно добавляю отдельно
safe pipe
многоразовый компонент, как указано ниже
# Add Safe Pipe
import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
@Pipe({name: 'mySafe'})
export class SafePipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {
}
public transform(url) {
return this.sanitizer.bypassSecurityTrustResourceUrl(url);
}
}
# then create shared pipe module as following
import { NgModule } from '@angular/core';
import { SafePipe } from './safe.pipe';
@NgModule({
declarations: [
SafePipe
],
exports: [
SafePipe
]
})
export class SharedPipesModule {
}
# import shared pipe module in your native module
@NgModule({
declarations: [],
imports: [
SharedPipesModule,
],
})
export class SupportModule {
}
<!-------------------
call your url (`trustedUrl` for me) and add `mySafe` as defined in Safe Pipe
---------------->
<div class="container-fluid" *ngIf="trustedUrl">
<iframe [src]="trustedUrl | mySafe" align="middle" width="100%" height="800" frameborder="0"></iframe>
</div>
Вот лучшая и проверенная безопасная труба:
import { Pipe, PipeTransform, SecurityContext } from '@angular/core';
import {
DomSanitizer,
SafeHtml,
SafeResourceUrl,
SafeScript,
SafeStyle,
SafeUrl,
SafeValue,
} from '@angular/platform-browser';
@Pipe({
name: 'safe',
})
export class SafePipe implements PipeTransform {
constructor(private readonly domSanitizer: DomSanitizer) {}
transform(
value: string | undefined,
type: string,
bypass: boolean
):
| SafeHtml
| SafeStyle
| SafeScript
| SafeUrl
| SafeResourceUrl
| SafeValue
| null {
if (!value) {
return null;
}
switch (type) {
case 'style':
return bypass
? this.domSanitizer.bypassSecurityTrustStyle(value)
: this.domSanitizer.sanitize(SecurityContext.STYLE, value);
case 'script':
return bypass
? this.domSanitizer.bypassSecurityTrustScript(value)
: this.domSanitizer.sanitize(SecurityContext.SCRIPT, value);
case 'url':
return bypass
? this.domSanitizer.bypassSecurityTrustUrl(value)
: this.domSanitizer.sanitize(SecurityContext.URL, value);
case 'resourceUrl':
return bypass
? this.domSanitizer.bypassSecurityTrustResourceUrl(value)
: this.domSanitizer.sanitize(SecurityContext.RESOURCE_URL, value);
default:
return bypass
? this.domSanitizer.bypassSecurityTrustHtml(value)
: this.domSanitizer.sanitize(SecurityContext.HTML, value);
}
}
}
import { DomSanitizer } from '@angular/platform-browser';
import { SafePipe } from './safe.pipe';
const mockDomSanitizer = ({
sanitize: jest.fn(),
bypassSecurityTrustHtml: jest.fn(),
bypassSecurityTrustStyle: jest.fn(),
bypassSecurityTrustUrl: jest.fn(),
bypassSecurityTrustResourceUrl: jest.fn(),
bypassSecurityTrustScript: jest.fn(),
} as unknown) as DomSanitizer;
describe('SafePipe', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should return null value when value received is undefined', () => {
const pipe = new SafePipe(mockDomSanitizer);
expect(pipe.transform(undefined, 'style', true)).toBeNull();
});
test.each([
{ a: 'style', b: true, expected: 'bypassSecurityTrustStyle' },
{ a: 'script', b: true, expected: 'bypassSecurityTrustScript' },
{ a: 'url', b: true, expected: 'bypassSecurityTrustUrl' },
{ a: 'resourceUrl', b: true, expected: 'bypassSecurityTrustResourceUrl' },
{ a: 'html', b: true, expected: 'bypassSecurityTrustHtml' },
])('should call the correspondent method', ({ a, b, expected }) => {
const pipe = new SafePipe(mockDomSanitizer);
pipe.transform('value', a, b);
const domSanitizer = mockDomSanitizer as never;
expect(domSanitizer[expected]).toHaveBeenCalled();
});
test.each([
{ a: 'style', b: false, expected: 'sanitize' },
{ a: 'script', b: false, expected: 'sanitize' },
{ a: 'url', b: false, expected: 'sanitize' },
{ a: 'resourceUrl', b: false, expected: 'sanitize' },
{ a: 'html', b: false, expected: 'sanitize' },
])('should call the correspondent method', ({ a, b, expected }) => {
const pipe = new SafePipe(mockDomSanitizer);
pipe.transform('value', a, b);
const domSanitizer = mockDomSanitizer as never;
expect(domSanitizer[expected]).toHaveBeenCalled();
});
});
import {DomSanitizationService} from '@angular/platform-browser';
@Component({
templateUrl: 'build/pages/veeu/veeu.html'
})
export class VeeUPage {
trustedURL:any;
static get parameters() {
return [NavController, App, MenuController,
DomSanitizationService];
}
constructor(nav, app, menu, sanitizer) {
this.app = app;
this.nav = nav;
this.menu = menu;
this.sanitizer = sanitizer;
this.trustedURL = sanitizer.bypassSecurityTrustUrl(this.mediaItems[1].url);
}
}
<iframe [src]='trustedURL' width="640" height="360" frameborder="0"
webkitallowfullscreen mozallowfullscreen allowfullscreen>
</iframe>
User property binding instead of function.
<img class='photo-img' [hidden]="!showPhoto1" src="data:image/jpeg;base64,{{theMediaItem.photoURL1}}">
Можно установить изображение как фоновое, чтобы избежать unsafe url
ошибка:
<div [style.backgroundImage]="'url(' + imageUrl + ')'" class="show-image"></div>
CSS:
.show-image {
width: 100px;
height: 100px;
border-radius: 50%;
background-size: cover;
}