MsalInterceptor未给img、音视频及PDF控件请求添加Bearer令牌
问题原因及解决方案
MsalInterceptor 仅会拦截通过 Angular HttpClient 发起的请求,而 img、video、audio 这类标签的 src 请求是由浏览器直接发起的,不走 HttpClient 的请求链路,所以拦截器无法自动为这些请求添加 Bearer 令牌。
解决方法
方法一:通过 HttpClient 获取资源并转换为 Object URL
这是最常用且安全的方式,让资源请求走 HttpClient 通道,确保拦截器能注入令牌:
- 在组件中使用 HttpClient 发起资源请求,指定
responseType: 'blob' - 将返回的 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
相关产品推荐
相关产品推荐

