mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-22 19:00:01 +08:00
优化rtsp鉴权事件
This commit is contained in:
parent
20d3757986
commit
8d1801339c
@ -85,8 +85,9 @@ on_publish=https://127.0.0.1/index/hook/on_publish
|
|||||||
on_record_mp4=https://127.0.0.1/index/hook/on_record_mp4
|
on_record_mp4=https://127.0.0.1/index/hook/on_record_mp4
|
||||||
#rtsp播放鉴权事件,此事件中比对rtsp的用户名密码
|
#rtsp播放鉴权事件,此事件中比对rtsp的用户名密码
|
||||||
on_rtsp_auth=https://127.0.0.1/index/hook/on_rtsp_auth
|
on_rtsp_auth=https://127.0.0.1/index/hook/on_rtsp_auth
|
||||||
#rtsp播放是否开启鉴权事件,置空则关闭rtsp鉴权。rtsp播放鉴权还支持url方式鉴权
|
#rtsp播放是否开启专属鉴权事件,置空则关闭rtsp鉴权。rtsp播放鉴权还支持url方式鉴权
|
||||||
#建议开发者统一采用url参数方式鉴权,rtsp用户名密码鉴权一般在设备上用的比较多
|
#建议开发者统一采用url参数方式鉴权,rtsp用户名密码鉴权一般在设备上用的比较多
|
||||||
|
#开启rtsp专属鉴权后,将不再触发on_play鉴权事件
|
||||||
on_rtsp_realm=https://127.0.0.1/index/hook/on_rtsp_realm
|
on_rtsp_realm=https://127.0.0.1/index/hook/on_rtsp_realm
|
||||||
#远程telnet调试鉴权事件
|
#远程telnet调试鉴权事件
|
||||||
on_shell_login=https://127.0.0.1/index/hook/on_shell_login
|
on_shell_login=https://127.0.0.1/index/hook/on_shell_login
|
||||||
|
@ -318,38 +318,80 @@ void RtspSession::handleReq_RECORD(const Parser &parser){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RtspSession::handleReq_Describe(const Parser &parser) {
|
void RtspSession::emitOnPlay(){
|
||||||
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
|
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
|
||||||
|
//url鉴权回调
|
||||||
|
auto onRes = [weakSelf](const string &err) {
|
||||||
|
auto strongSelf = weakSelf.lock();
|
||||||
|
if (!strongSelf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!err.empty()) {
|
||||||
|
//播放url鉴权失败
|
||||||
|
strongSelf->sendRtspResponse("401 Unauthorized", {"Content-Type", "text/plain"}, err);
|
||||||
|
strongSelf->shutdown(SockException(Err_shutdown, StrPrinter << "401 Unauthorized:" << err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
strongSelf->onAuthSuccess();
|
||||||
|
};
|
||||||
|
|
||||||
|
Broadcast::AuthInvoker invoker = [weakSelf, onRes](const string &err) {
|
||||||
|
auto strongSelf = weakSelf.lock();
|
||||||
|
if (!strongSelf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
strongSelf->async([onRes, err, weakSelf]() {
|
||||||
|
onRes(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
//广播通用播放url鉴权事件
|
||||||
|
auto flag = _emit_on_play ? false : NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed, _mediaInfo, invoker, static_cast<SockInfo &>(*this));
|
||||||
|
if (!flag) {
|
||||||
|
//该事件无人监听,默认不鉴权
|
||||||
|
onRes("");
|
||||||
|
}
|
||||||
|
//已经鉴权过了
|
||||||
|
_emit_on_play = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtspSession::handleReq_Describe(const Parser &parser) {
|
||||||
//该请求中的认证信息
|
//该请求中的认证信息
|
||||||
auto authorization = parser["Authorization"];
|
auto authorization = parser["Authorization"];
|
||||||
onGetRealm invoker = [weakSelf,authorization](const string &realm){
|
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
|
||||||
|
//rtsp专属鉴权是否开启事件回调
|
||||||
|
onGetRealm invoker = [weakSelf, authorization](const string &realm) {
|
||||||
auto strongSelf = weakSelf.lock();
|
auto strongSelf = weakSelf.lock();
|
||||||
if(!strongSelf){
|
if (!strongSelf) {
|
||||||
//本对象已经销毁
|
//本对象已经销毁
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//切换到自己的线程然后执行
|
//切换到自己的线程然后执行
|
||||||
strongSelf->async([weakSelf,realm,authorization](){
|
strongSelf->async([weakSelf, realm, authorization]() {
|
||||||
auto strongSelf = weakSelf.lock();
|
auto strongSelf = weakSelf.lock();
|
||||||
if(!strongSelf){
|
if (!strongSelf) {
|
||||||
//本对象已经销毁
|
//本对象已经销毁
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(realm.empty()){
|
if (realm.empty()) {
|
||||||
//无需认证,回复sdp
|
//无需rtsp专属认证, 那么继续url通用鉴权认证(on_play)
|
||||||
strongSelf->onAuthSuccess();
|
strongSelf->emitOnPlay();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//该流需要认证
|
//该流需要rtsp专属认证,开启rtsp专属认证后,将不再触发url通用鉴权认证(on_play)
|
||||||
strongSelf->onAuthUser(realm,authorization);
|
strongSelf->_rtsp_realm = realm;
|
||||||
|
strongSelf->onAuthUser(realm, authorization);
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//广播是否需要认证事件
|
if(_rtsp_realm.empty()){
|
||||||
if(!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnGetRtspRealm,_mediaInfo,invoker,static_cast<SockInfo &>(*this))){
|
//广播是否需要rtsp专属认证事件
|
||||||
//无人监听此事件,说明无需认证
|
if (!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnGetRtspRealm, _mediaInfo, invoker, static_cast<SockInfo &>(*this))) {
|
||||||
invoker("");
|
//无人监听此事件,说明无需认证
|
||||||
|
invoker("");
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
invoker(_rtsp_realm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void RtspSession::onAuthSuccess() {
|
void RtspSession::onAuthSuccess() {
|
||||||
@ -725,113 +767,75 @@ void RtspSession::handleReq_Play(const Parser &parser) {
|
|||||||
send_SessionNotFound();
|
send_SessionNotFound();
|
||||||
throw SockException(Err_shutdown,_aTrackInfo.empty() ? "can not find any availabe track when play" : "session not found when play");
|
throw SockException(Err_shutdown,_aTrackInfo.empty() ? "can not find any availabe track when play" : "session not found when play");
|
||||||
}
|
}
|
||||||
|
auto pMediaSrc = _pMediaSrc.lock();
|
||||||
|
if(!pMediaSrc){
|
||||||
|
send_StreamNotFound();
|
||||||
|
shutdown(SockException(Err_shutdown,"rtsp stream released"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool useBuf = true;
|
||||||
|
_enableSendRtp = false;
|
||||||
|
float iStartTime = 0;
|
||||||
auto strRange = parser["Range"];
|
auto strRange = parser["Range"];
|
||||||
auto onRes = [this,strRange](const string &err){
|
if (strRange.size()) {
|
||||||
bool authSuccess = err.empty();
|
//这个是seek操作
|
||||||
if(!authSuccess){
|
auto strStart = FindField(strRange.data(), "npt=", "-");
|
||||||
//第一次play是播放,否则是恢复播放。只对播放鉴权
|
if (strStart == "now") {
|
||||||
sendRtspResponse("401 Unauthorized", {"Content-Type", "text/plain"}, err);
|
strStart = "0";
|
||||||
shutdown(SockException(Err_shutdown,StrPrinter << "401 Unauthorized:" << err));
|
}
|
||||||
|
iStartTime = 1000 * atof(strStart.data());
|
||||||
|
InfoP(this) << "rtsp seekTo(ms):" << iStartTime;
|
||||||
|
useBuf = !pMediaSrc->seekTo(iStartTime);
|
||||||
|
} else if (pMediaSrc->totalReaderCount() == 0) {
|
||||||
|
//第一个消费者
|
||||||
|
pMediaSrc->seekTo(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
_StrPrinter rtp_info;
|
||||||
|
for (auto &track : _aTrackInfo) {
|
||||||
|
if (track->_inited == false) {
|
||||||
|
//还有track没有setup
|
||||||
|
shutdown(SockException(Err_shutdown, "track not setuped"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
track->_ssrc = pMediaSrc->getSsrc(track->_type);
|
||||||
|
track->_seq = pMediaSrc->getSeqence(track->_type);
|
||||||
|
track->_time_stamp = pMediaSrc->getTimeStamp(track->_type);
|
||||||
|
|
||||||
auto pMediaSrc = _pMediaSrc.lock();
|
rtp_info << "url=" << _strContentBase << "/" << track->_control_surffix << ";"
|
||||||
if(!pMediaSrc){
|
<< "seq=" << track->_seq << ";"
|
||||||
send_StreamNotFound();
|
<< "rtptime=" << (int) (track->_time_stamp * (track->_samplerate / 1000)) << ",";
|
||||||
shutdown(SockException(Err_shutdown,"rtsp stream released"));
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool useBuf = true;
|
rtp_info.pop_back();
|
||||||
_enableSendRtp = false;
|
sendRtspResponse("200 OK",
|
||||||
float iStartTime = 0;
|
{"Range", StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << (useBuf? pMediaSrc->getTimeStamp(TrackInvalid) / 1000.0 : iStartTime / 1000),
|
||||||
if (strRange.size() && !_bFirstPlay) {
|
"RTP-Info",rtp_info
|
||||||
//这个是seek操作
|
});
|
||||||
auto strStart = FindField(strRange.data(), "npt=", "-");
|
|
||||||
if (strStart == "now") {
|
|
||||||
strStart = "0";
|
|
||||||
}
|
|
||||||
iStartTime = 1000 * atof(strStart.data());
|
|
||||||
InfoP(this) << "rtsp seekTo(ms):" << iStartTime;
|
|
||||||
useBuf = !pMediaSrc->seekTo(iStartTime);
|
|
||||||
}else if(pMediaSrc->totalReaderCount() == 0){
|
|
||||||
//第一个消费者
|
|
||||||
pMediaSrc->seekTo(0);
|
|
||||||
}
|
|
||||||
_bFirstPlay = false;
|
|
||||||
|
|
||||||
_StrPrinter rtp_info;
|
_enableSendRtp = true;
|
||||||
for(auto &track : _aTrackInfo){
|
setSocketFlags();
|
||||||
if (track->_inited == false) {
|
|
||||||
//还有track没有setup
|
|
||||||
shutdown(SockException(Err_shutdown,"track not setuped"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
track->_ssrc = pMediaSrc->getSsrc(track->_type);
|
|
||||||
track->_seq = pMediaSrc->getSeqence(track->_type);
|
|
||||||
track->_time_stamp = pMediaSrc->getTimeStamp(track->_type);
|
|
||||||
|
|
||||||
rtp_info << "url=" << _strContentBase << "/" << track->_control_surffix << ";"
|
if (!_pRtpReader && _rtpType != Rtsp::RTP_MULTICAST) {
|
||||||
<< "seq=" << track->_seq << ";"
|
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
|
||||||
<< "rtptime=" << (int)(track->_time_stamp * (track->_samplerate / 1000)) << ",";
|
_pRtpReader = pMediaSrc->getRing()->attach(getPoller(), useBuf);
|
||||||
}
|
_pRtpReader->setDetachCB([weakSelf]() {
|
||||||
|
|
||||||
rtp_info.pop_back();
|
|
||||||
|
|
||||||
sendRtspResponse("200 OK",
|
|
||||||
{"Range", StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << (useBuf? pMediaSrc->getTimeStamp(TrackInvalid) / 1000.0 : iStartTime / 1000),
|
|
||||||
"RTP-Info",rtp_info
|
|
||||||
});
|
|
||||||
|
|
||||||
_enableSendRtp = true;
|
|
||||||
setSocketFlags();
|
|
||||||
|
|
||||||
if (!_pRtpReader && _rtpType != Rtsp::RTP_MULTICAST) {
|
|
||||||
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
|
|
||||||
_pRtpReader = pMediaSrc->getRing()->attach(getPoller(),useBuf);
|
|
||||||
_pRtpReader->setDetachCB([weakSelf]() {
|
|
||||||
auto strongSelf = weakSelf.lock();
|
|
||||||
if(!strongSelf) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
strongSelf->shutdown(SockException(Err_shutdown,"rtsp ring buffer detached"));
|
|
||||||
});
|
|
||||||
_pRtpReader->setReadCB([weakSelf](const RtspMediaSource::RingDataType &pack) {
|
|
||||||
auto strongSelf = weakSelf.lock();
|
|
||||||
if(!strongSelf) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(strongSelf->_enableSendRtp) {
|
|
||||||
strongSelf->sendRtpPacket(pack);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
|
|
||||||
Broadcast::AuthInvoker invoker = [weakSelf,onRes](const string &err){
|
|
||||||
auto strongSelf = weakSelf.lock();
|
|
||||||
if(!strongSelf){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
strongSelf->async([weakSelf,onRes,err](){
|
|
||||||
auto strongSelf = weakSelf.lock();
|
auto strongSelf = weakSelf.lock();
|
||||||
if(!strongSelf){
|
if (!strongSelf) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
onRes(err);
|
strongSelf->shutdown(SockException(Err_shutdown, "rtsp ring buffer detached"));
|
||||||
|
});
|
||||||
|
_pRtpReader->setReadCB([weakSelf](const RtspMediaSource::RingDataType &pack) {
|
||||||
|
auto strongSelf = weakSelf.lock();
|
||||||
|
if (!strongSelf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (strongSelf->_enableSendRtp) {
|
||||||
|
strongSelf->sendRtpPacket(pack);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
|
||||||
if(_bFirstPlay){
|
|
||||||
//第一次收到play命令,需要鉴权
|
|
||||||
auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed,_mediaInfo,invoker,static_cast<SockInfo &>(*this));
|
|
||||||
if(!flag){
|
|
||||||
//该事件无人监听,默认不鉴权
|
|
||||||
onRes("");
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
//后面是seek或恢复命令,不需要鉴权
|
|
||||||
onRes("");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,6 +160,8 @@ private:
|
|||||||
void onAuthBasic(const string &realm,const string &strBase64);
|
void onAuthBasic(const string &realm,const string &strBase64);
|
||||||
//校验md5方式的认证加密
|
//校验md5方式的认证加密
|
||||||
void onAuthDigest(const string &realm,const string &strMd5);
|
void onAuthDigest(const string &realm,const string &strMd5);
|
||||||
|
//触发url鉴权事件
|
||||||
|
void emitOnPlay();
|
||||||
|
|
||||||
//发送rtp给客户端
|
//发送rtp给客户端
|
||||||
void sendRtpPacket(const RtspMediaSource::RingDataType &pkt);
|
void sendRtpPacket(const RtspMediaSource::RingDataType &pkt);
|
||||||
@ -179,8 +181,10 @@ private:
|
|||||||
string _strContentBase;
|
string _strContentBase;
|
||||||
//Session号
|
//Session号
|
||||||
string _strSession;
|
string _strSession;
|
||||||
//是否第一次播放,第一次播放需要鉴权,第二次播放属于暂停恢复
|
//记录是否需要rtsp专属鉴权,防止重复触发事件
|
||||||
bool _bFirstPlay = true;
|
string _rtsp_realm;
|
||||||
|
//是否已经触发on_play事件
|
||||||
|
bool _emit_on_play = false;
|
||||||
//url解析后保存的相关信息
|
//url解析后保存的相关信息
|
||||||
MediaInfo _mediaInfo;
|
MediaInfo _mediaInfo;
|
||||||
//rtsp播放器绑定的直播源
|
//rtsp播放器绑定的直播源
|
||||||
|
Loading…
Reference in New Issue
Block a user