admin管理员组文章数量:1403480
I have secured endpoint. I need to pass a jwt token in the head of a Http Get request from Angular to stream the video.
The endpoint in a dotnet core controller looks like this (simplified):
[Route("api/GetVideo/{videoId}")]
public async Task<IActionResult> GetVideoAsync(int videoId)
{
string videoFilePath = GiveMeTheVideoFilePath(videoId);
return this.PhysicalFile(videoFilePath, "application/octet-stream", enableRangeProcessing: true);
}
Angular code: videoponent.html
<video width="100%" height="320" crossorigin="anonymous" controls #videoElement>
<source
[src]="'http://mydomain/api/GetVideo/1' | authVideo | async" type="application/octet-stream"
/>
</video>
video.pipe.ts
@Pipe({
name: 'authVideo',
})
export class AuthVideoPipe implements PipeTransform {
constructor(private http: HttpClient, private auth: AuthTokenService) {}
transform(url: string) {
return new Observable<string>(observer => {
const token = this.auth.getToken(); //this line gets the jwt token
const headers = new HttpHeaders({ Authorization: `Bearer ${token}` });
const { next, error } = observer;
return this.http.get(url, { headers, responseType: 'blob' }).subscribe(response => {
const reader = new FileReader();
reader.readAsDataURL(response);
reader.onloadend = function() {
observer.next(reader.result as string);
};
});
});
}
}
It does make a get request to the endpoint with the above code. And something is returned to the front-end. But the video is not playing. I found the above way from this SO question. It works for images, but that doesn't work for video apparently. My thought is that I might need to read the streams byte by byte in the front-end. If so, how do I do that?
I have tried changing "application/octet-stream" to "video/mp4" on both ends. But no luck.
Note that when I removed security code from the back-end, and removed the authVideo pipe from the html it works perfectly. Please shed me some light. Thank you!
I have secured endpoint. I need to pass a jwt token in the head of a Http Get request from Angular to stream the video.
The endpoint in a dotnet core controller looks like this (simplified):
[Route("api/GetVideo/{videoId}")]
public async Task<IActionResult> GetVideoAsync(int videoId)
{
string videoFilePath = GiveMeTheVideoFilePath(videoId);
return this.PhysicalFile(videoFilePath, "application/octet-stream", enableRangeProcessing: true);
}
Angular code: video.ponent.html
<video width="100%" height="320" crossorigin="anonymous" controls #videoElement>
<source
[src]="'http://mydomain/api/GetVideo/1' | authVideo | async" type="application/octet-stream"
/>
</video>
video.pipe.ts
@Pipe({
name: 'authVideo',
})
export class AuthVideoPipe implements PipeTransform {
constructor(private http: HttpClient, private auth: AuthTokenService) {}
transform(url: string) {
return new Observable<string>(observer => {
const token = this.auth.getToken(); //this line gets the jwt token
const headers = new HttpHeaders({ Authorization: `Bearer ${token}` });
const { next, error } = observer;
return this.http.get(url, { headers, responseType: 'blob' }).subscribe(response => {
const reader = new FileReader();
reader.readAsDataURL(response);
reader.onloadend = function() {
observer.next(reader.result as string);
};
});
});
}
}
It does make a get request to the endpoint with the above code. And something is returned to the front-end. But the video is not playing. I found the above way from this SO question. It works for images, but that doesn't work for video apparently. My thought is that I might need to read the streams byte by byte in the front-end. If so, how do I do that?
I have tried changing "application/octet-stream" to "video/mp4" on both ends. But no luck.
Note that when I removed security code from the back-end, and removed the authVideo pipe from the html it works perfectly. Please shed me some light. Thank you!
Share Improve this question edited Apr 19, 2021 at 17:49 Avinash Reddy 9378 silver badges23 bronze badges asked Aug 1, 2020 at 0:27 Lok CLok C 4011 gold badge5 silver badges15 bronze badges 4- how did you slove this issue – Avinash Reddy Commented Apr 18, 2021 at 23:59
- I end up moving the video streaming endpoint behind a domain that is guard by a security service. So, whoever opens the video endpoints without login will be redirected to the login page. When the user is logged in, the video can be streamed via a normal HTML video tag. The downside is that whoever consuming the video endpoint has to repeat the code in the controller. If you have to create a standalone video streaming service, you can consider calling the video service from a secured backend. That way you don't need to expose the actual service endpoint to the client. – Lok C Commented Apr 19, 2021 at 20:25
- "you can consider calling the video service from a secured backend" can you tell me more about this. it will be really helpful. my application is like user can post the video and only login user has to see the video. videos are not supposed to be public. – Avinash Reddy Commented Apr 20, 2021 at 2:40
- you can try get only the endpoint first? – Rene Arias Commented Apr 24, 2021 at 2:01
2 Answers
Reset to default 3While this solution works for images because all of the data is loaded once as a data URL, you shouldn't be doing this for a video as it disables the streaming ability of the browser. Indeed by doing this you are loading the entire video in memory before transforming it into a data URL, which is really bad in terms of performance and user experience (requires the full video to be loaded before playing it, and causes heavy memory consumption).
The obvious solution to your problem is to use cookies for authentication:
- A cookie is set when the authentication succeeds
- It is automatically sent back in subsequent requests, including the video one
In the following I'm assuming you can't do that for some reason.
You could use MediaSource. It allows you to control the actual request that is sent to retrieve the video (and add the Authorization
header).
Note that even if this is widely supported by all of the browsers, this is experimental.
Your code should look like this:
assetURL = 'http://mydomain/api/GetVideo/1';
// Modify this with the actual mime type and codec
mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
@ViewChild("videoElement") video: ElementRef;
ngAfterViewInit() {
if (
"MediaSource" in window &&
MediaSource.isTypeSupported(this.mimeCodec)
) {
const mediaSource = new MediaSource();
(this.video.nativeElement as HTMLVideoElement).src = URL.createObjectURL(
mediaSource
);
mediaSource.addEventListener("sourceopen", () =>
this.sourceOpen(mediaSource)
);
} else {
console.error("Unsupported MIME type or codec: ", this.mimeCodec);
}
}
sourceOpen(mediaSource) {
const sourceBuffer = mediaSource.addSourceBuffer(this.mimeCodec);
const token = this.auth.getToken(); //this line gets the jwt token
const headers = new HttpHeaders({ Authorization: `Bearer ${token}` });
return this.http
.get(this.assetURL, { headers, responseType: "blob" })
.subscribe(blob => {
sourceBuffer.addEventListener("updateend", () => {
mediaSource.endOfStream();
this.video.nativeElement.play();
});
blob.arrayBuffer().then(x => sourceBuffer.appendBuffer(x));
});
}
This working demo gives the following result:
In my case, the URI of the webApi is the same as the main application, which is gaurded by an authentication service. The flow basically works like this:
Before a request has reached the webApi endpoint, the authenticationService will determine whether the user is allowed to view this endpoint. e.g. whether the user is logged in, does the user have permission to view this endpoint, etc.
If a request has e to the webApi controller, the rest is pretty simple. It can just call the method in the videoService that returns the video stream.
In the frontend, all you need is this(of course you can make the videoId dynamic):
<video width="100%" height="320" controls #videoElement>
<source
[src]="'http://mydomain/api/GetVideo/1' | async"
/>
</video>
The back will look like this:
[Route("api")]
public class WebApiController : Controller
{
[HttpGet("GetVideo/{videoId}")]
public async Task<IActionResult> GetVideoAsync(int videoId)
{
// Note: videoService can be on the same server, or a service
// on a different server depends on how you implement it
return this.videoService.GetVideoStream(videoId);
}
}
本文标签: javascriptStream video from a secured endpoint using AngularStack Overflow
版权声明:本文标题:javascript - Stream video from a secured endpoint using Angular - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744334054a2601102.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论