Ressource externe non chargée par AngularJs

195

En utilisant Angular et Phonegap, j'essaie de charger une vidéo qui se trouve sur un serveur distant mais qui a rencontré un problème. Dans mon JSON, l'URL est entrée comme URL HTTP ordinaire.

"src" : "http://www.somesite.com/myvideo.mp4"

Mon modèle vidéo

 <video controls poster="img/poster.png">
       <source ng-src="{{object.src}}" type="video/mp4"/>
 </video>

Toutes mes autres données sont chargées mais quand je regarde ma console, j'obtiens cette erreur:

Error: [$interpolate:interr] Can't interpolate: {{object.src}}
Error: [$sce:insecurl] Blocked loading resource from url not allowed by $sceDelegate policy.  URL

J'ai essayé d'ajouter $compileProviderma configuration, mais cela n'a pas résolu mon problème.

$compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|tel):/);

J'ai vu cet article sur les problèmes interdomaines, mais je ne sais pas comment résoudre ce problème ni dans quelle direction je dois aller. Des idées? Toute aide est appréciée

mhartington
la source
1
Pourriez-vous également publier le config.xmlfichier de votre corodva ?
Andrew Shustariov du
1
En ce moment, je teste toujours dans le navigateur, donc je n'ai même pas commencé le débogage de l'intervalle téléphonique.
mhartington

Réponses:

267

C'est la seule solution qui a fonctionné pour moi:

var app = angular.module('plunker', ['ngSanitize']);

app.controller('MainCtrl', function($scope, $sce) {
  $scope.trustSrc = function(src) {
    return $sce.trustAsResourceUrl(src);
  }

  $scope.movie = {src:"http://www.youtube.com/embed/Lx7ycjC8qjE", title:"Egghead.io AngularJS Binding"};
});

Puis dans un iframe:

<iframe class="youtube-player" type="text/html" width="640" height="385"
        ng-src="{{trustSrc(movie.src)}}" allowfullscreen frameborder="0">
</iframe>

http://plnkr.co/edit/tYq22VjwB10WmytQO9Pb?p=preview

Guy Sopher
la source
Est-ce possible sans iFrame? J'ai besoin d'intégrer une vidéo où les informations de session déterminent si le consommateur est autorisé à voir la vidéo ou non. Les informations de session ne sont pas transmises via l'iFrame.
Blake
sympa, si vous pouvez utiliser iframe
Ringo
270

Une autre solution simple consiste à créer un filtre:

app.filter('trusted', ['$sce', function ($sce) {
    return function(url) {
        return $sce.trustAsResourceUrl(url);
    };
}]);

Spécifiez ensuite le filtre dans ng-src:

<video controls poster="img/poster.png">
       <source ng-src="{{object.src | trusted}}" type="video/mp4"/>
</video>
David Boyd
la source
22
Certainement la solution la plus élégante et angulaire.
Sc0ttyD
1
A fonctionné pour moi, et en effet c'est plus agréable que d'utiliser un iframe.
Thomas Amar
1
Meilleure réponse, esprit plus angulaire et cela a fonctionné là où les autres solutions ne l'ont pas été pour certaines raisons. Merci beaucoup!
floribon
76

Mettre la ressource en liste blanche avec $ sceDelegateProvider

Cela est dû à une nouvelle politique de sécurité mise en place dans Angular 1.2. Il rend XSS plus difficile en empêchant un pirate de composer un numéro (c'est-à-dire en faisant une demande à une URL étrangère, contenant potentiellement une charge utile).

Pour le contourner correctement, vous devez mettre en liste blanche les domaines que vous souhaitez autoriser, comme ceci:

angular.module('myApp',['ngSanitize']).config(function($sceDelegateProvider) {
  $sceDelegateProvider.resourceUrlWhitelist([
    // Allow same origin resource loads.
    'self',
    // Allow loading from our assets domain.  Notice the difference between * and **.
    'http://srv*.assets.example.com/**'
  ]);

  // The blacklist overrides the whitelist so the open redirect here is blocked.
  $sceDelegateProvider.resourceUrlBlacklist([
    'http://myapp.example.com/clickThru**'
  ]);
});

Cet exemple est extrait de la documentation que vous pouvez lire ici:

https://docs.angularjs.org/api/ng/provider/$sceDelegateProvider

Assurez-vous d'inclure ngSanitize dans votre application pour que cela fonctionne.

Désactiver la fonction

Si vous souhaitez désactiver cette fonctionnalité utile et que vous êtes sûr que vos données sont sécurisées, vous pouvez simplement autoriser **, comme ceci:

angular.module('app').config(function($sceDelegateProvider) {
  $sceDelegateProvider.resourceUrlWhitelist(['**']);
});
superluminaire
la source
2
Remarque: si resourceUrlWhitelistcela ne fonctionne pas pour vous, vérifiez si vous n'avez pas de double barre oblique après le nom de domaine (facile pour cela lors de la concaténation de trucs à partir de variables et ils ont tous les deux des barres obliques)
jakub.g
2
Il s'agit d'un moyen plus propre, global et sûr de contourner ce problème.
DJ.
"Appel sortant" n'est pas un bon terme à utiliser pour quelqu'un qui essaie de comprendre le problème.
Ringo
1
Merci @Ringo - J'ai ajouté un commentaire pour clarifier.
superluminaire du
21

Eu le même problème ici. J'avais besoin de me lier aux liens Youtube. Ce qui a fonctionné pour moi, en tant que solution globale , a été d'ajouter ce qui suit à ma configuration:

.config(['$routeProvider', '$sceDelegateProvider',
        function ($routeProvider, $sceDelegateProvider) {

    $sceDelegateProvider.resourceUrlWhitelist(['self', new RegExp('^(http[s]?):\/\/(w{3}.)?youtube\.com/.+$')]);

}]);

L'ajout de «self» est important - sinon, il ne sera pas possible de se lier à une URL. Des documents angulaires

'self' - La chaîne spéciale, 'self', peut être utilisée pour correspondre à toutes les URL du même domaine que le document d'application en utilisant le même protocole.

Avec cela en place, je suis maintenant capable de me lier directement à n'importe quel lien Youtube.

Vous devrez évidemment personnaliser l'expression régulière selon vos besoins. J'espère que ça aide!

zumek
la source
4

La solution la meilleure et la plus simple pour résoudre ce problème consiste à transmettre vos données à partir de cette fonction dans le contrôleur.

$scope.trustSrcurl = function(data) 
{
    return $sce.trustAsResourceUrl(data);
}

Dans la page html

<iframe class="youtube-player" type="text/html" width="640" height="385" ng-src="{{trustSrcurl(video.src)}}" allowfullscreen frameborder="0"></iframe>
Kajal M. Bambhaniya
la source
2

J'ai rencontré le même problème en utilisant Videogular. J'obtenais ce qui suit lors de l'utilisation de ng-src:

Error: [$interpolate:interr] Can't interpolate: {{url}}
Error: [$sce:insecurl] Blocked loading resource from url not allowed by $sceDelegate policy

J'ai résolu le problème en écrivant une directive de base:

angular.module('app').directive('dynamicUrl', function () {
return {
  restrict: 'A',
  link: function postLink(scope, element, attrs) {
    element.attr('src', scope.content.fullUrl);
  }
};
});

Le html:

 <div videogular vg-width="200" vg-height="300" vg-theme="config.theme">
    <video class='videoPlayer' controls preload='none'>
          <source dynamic-url src='' type='{{ content.mimeType }}'>
    </video>
 </div>
cagan
la source
2

Si quelqu'un cherche une solution TypeScript:

Fichier .ts (modifiez les variables le cas échéant):

module App.Filters {

    export class trustedResource {

        static $inject:string[] = ['$sce'];

        static filter($sce:ng.ISCEService) {
            return (value) => {
                return $sce.trustAsResourceUrl(value)
            };
        }
    }
}
filters.filter('trustedResource', App.Filters.trusted.filter);

Html:

<video controls ng-if="HeaderVideoUrl != null">
  <source ng-src="{{HeaderVideoUrl | trustedResource}}" type="video/mp4"/>
</video>
GONeale
la source
1

Sur la base du message d'erreur, votre problème semble être lié à l' interpolation (généralement votre expression {{}}), pas à un problème interdomaine. ng-src="{{object.src}}"Suce fondamentalement .

ng-srca été conçu avec le imgtag à l'esprit IMO. Cela pourrait ne pas convenir <source>. Voir http://docs.angularjs.org/api/ng.directive:ngSrc

Si vous déclarez <source src="somesite.com/myvideo.mp4"; type="video/mp4"/>, cela fonctionnera, non? (notez que je retire ng-srcen faveur de src) Sinon il faut d'abord le corriger.

Assurez-vous ensuite que {{object.src}}renvoie la valeur attendue (en dehors de <video>):

<span>{{object.src}}</span>
<video>...</video>

S'il renvoie la valeur attendue, l'instruction suivante devrait fonctionner:

<source src="{{object.src}}"; type="video/mp4"/> //src instead of ng-src
Roland
la source
En utilisant simplement src et en codant en dur l'url, tout fonctionne comme je le souhaite. Dès que j'utilise {{object.src}} bien que l'attribut src ne soit même pas passé par la pensée. Je suis allé de l'avant et j'ai même supprimé la balise source et mis le src en ligne avec la balise vidéo, mais toujours rien
mhartington
Je veux dire, êtes-vous sûr que {{object.src}} renvoie une valeur? Il peut retourner indéfini.
roland
{{object.src}} renvoie une valeur. Testé en utilisant un <p> </p> et un <a> </a>
mhartington
1
Je vais probablement devoir le faire, j'ai déjà trouvé cela et ça a l'air plutôt bien. videogular.com/# . Merci pour l'aide
mhartington
2
Cela n'a rien à voir avec la ng-srcrupture (ce n'est pas le cas). Cela a à voir avec la politique de sécurité d'AngularJS: docs.angularjs.org/api/ng/service/$sce
Pauan
0

J'ai eu cette erreur dans les tests , la directive templateUrln'était pas fiable, mais uniquement pour la spécification, j'ai donc ajouté le répertoire du modèle:

beforeEach(angular.mock.module('app.templates'));

Mon répertoire principal est app.

écolo
la source