You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MsalInterceptor未给img、音视频及PDF控件请求添加Bearer令牌

问题原因及解决方案

MsalInterceptor 仅会拦截通过 Angular HttpClient 发起的请求,而 img、video、audio 这类标签的 src 请求是由浏览器直接发起的,不走 HttpClient 的请求链路,所以拦截器无法自动为这些请求添加 Bearer 令牌。

解决方法

方法一:通过 HttpClient 获取资源并转换为 Object URL

这是最常用且安全的方式,让资源请求走 HttpClient 通道,确保拦截器能注入令牌:

  1. 在组件中使用 HttpClient 发起资源请求,指定 responseType: 'blob'
  2. 将返回的 Blob 对象转换为安全的 Object URL,绑定到标签的 src 属性

示例代码:

// 组件代码
import { HttpClient } from '@angular/common/http';
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
import { Component, OnInit, OnDestroy } from '@angular/core';

@Component({
  selector: 'app-media-viewer',
  template: `<img [src]="imageUrl" alt="Protected Image">`
})
export class MediaViewerComponent implements OnInit, OnDestroy {
  imageUrl: SafeUrl | null = null;

  constructor(
    private http: HttpClient,
    private sanitizer: DomSanitizer
  ) {}

  ngOnInit() {
    this.loadProtectedImage();
  }

  private loadProtectedImage() {
    // 替换为你的受保护资源地址
    const resourceUrl = '/api/protected/images/hero';
    this.http.get(resourceUrl, { responseType: 'blob' }).subscribe(blob => {
      this.imageUrl = this.sanitizer.bypassSecurityTrustUrl(
        URL.createObjectURL(blob)
      );
    });
  }

  ngOnDestroy() {
    if (this.imageUrl) {
      const rawUrl = this.imageUrl.changingThisBreaksApplicationSecurity;
      URL.revokeObjectURL(rawUrl);
    }
  }
}

方法二:手动获取令牌并附加到资源请求(不推荐)

如果资源服务器支持通过查询参数传递令牌(注意:这种方式令牌会暴露在 URL 中,存在安全风险),可以手动调用 Msal 的 acquireTokenSilent 获取令牌,然后拼接成带令牌的 URL:

示例代码:

import { MsalService } from '@azure/msal-angular';
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-video-player',
  template: `<video [src]="videoUrl" controls></video>`
})
export class VideoPlayerComponent implements OnInit {
  videoUrl: SafeUrl | null = null;

  constructor(
    private msalService: MsalService,
    private sanitizer: DomSanitizer
  ) {}

  async ngOnInit() {
    await this.loadProtectedVideo();
  }

  private async loadProtectedVideo() {
    const resourceUrl = '/api/protected/videos/demo';
    const tokenResponse = await this.msalService.acquireTokenSilent({
      scopes: ['api://your-entraid-app-id/access_as_user'] // 替换为你的资源范围
    });
    const tokenizedUrl = `${resourceUrl}?access_token=${tokenResponse.accessToken}`;
    this.videoUrl = this.sanitizer.bypassSecurityTrustUrl(tokenizedUrl);
  }
}

关键说明

  • 方法一中必须在组件销毁时调用 URL.revokeObjectURL 释放内存,避免内存泄漏。
  • 方法二仅适用于对安全性要求较低的场景,不建议在生产环境中使用。

内容的提问来源于stack exchange,提问作者Jana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 16:10:13