优化rtsp鉴权事件

This commit is contained in:
xiongziliang 2020-05-25 18:22:21 +08:00
parent 20d3757986
commit 8d1801339c
3 changed files with 123 additions and 114 deletions

View File

@ -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

View File

@ -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("");
} }
} }

View File

@ -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播放器绑定的直播源