Commit 8d180133 by xiongziliang

优化rtsp鉴权事件

parent 20d37579
...@@ -85,8 +85,9 @@ on_publish=https://127.0.0.1/index/hook/on_publish ...@@ -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,39 +318,81 @@ void RtspSession::handleReq_RECORD(const Parser &parser){ ...@@ -318,39 +318,81 @@ 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() {
TraceP(this); TraceP(this);
...@@ -725,16 +767,6 @@ void RtspSession::handleReq_Play(const Parser &parser) { ...@@ -725,16 +767,6 @@ 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 strRange = parser["Range"];
auto onRes = [this,strRange](const string &err){
bool authSuccess = err.empty();
if(!authSuccess){
//第一次play是播放,否则是恢复播放。只对播放鉴权
sendRtspResponse("401 Unauthorized", {"Content-Type", "text/plain"}, err);
shutdown(SockException(Err_shutdown,StrPrinter << "401 Unauthorized:" << err));
return;
}
auto pMediaSrc = _pMediaSrc.lock(); auto pMediaSrc = _pMediaSrc.lock();
if(!pMediaSrc){ if(!pMediaSrc){
send_StreamNotFound(); send_StreamNotFound();
...@@ -745,7 +777,8 @@ void RtspSession::handleReq_Play(const Parser &parser) { ...@@ -745,7 +777,8 @@ void RtspSession::handleReq_Play(const Parser &parser) {
bool useBuf = true; bool useBuf = true;
_enableSendRtp = false; _enableSendRtp = false;
float iStartTime = 0; float iStartTime = 0;
if (strRange.size() && !_bFirstPlay) { auto strRange = parser["Range"];
if (strRange.size()) {
//这个是seek操作 //这个是seek操作
auto strStart = FindField(strRange.data(), "npt=", "-"); auto strStart = FindField(strRange.data(), "npt=", "-");
if (strStart == "now") { if (strStart == "now") {
...@@ -754,17 +787,16 @@ void RtspSession::handleReq_Play(const Parser &parser) { ...@@ -754,17 +787,16 @@ void RtspSession::handleReq_Play(const Parser &parser) {
iStartTime = 1000 * atof(strStart.data()); iStartTime = 1000 * atof(strStart.data());
InfoP(this) << "rtsp seekTo(ms):" << iStartTime; InfoP(this) << "rtsp seekTo(ms):" << iStartTime;
useBuf = !pMediaSrc->seekTo(iStartTime); useBuf = !pMediaSrc->seekTo(iStartTime);
}else if(pMediaSrc->totalReaderCount() == 0){ } else if (pMediaSrc->totalReaderCount() == 0) {
//第一个消费者 //第一个消费者
pMediaSrc->seekTo(0); pMediaSrc->seekTo(0);
} }
_bFirstPlay = false;
_StrPrinter rtp_info; _StrPrinter rtp_info;
for(auto &track : _aTrackInfo){ for (auto &track : _aTrackInfo) {
if (track->_inited == false) { if (track->_inited == false) {
//还有track没有setup //还有track没有setup
shutdown(SockException(Err_shutdown,"track not setuped")); shutdown(SockException(Err_shutdown, "track not setuped"));
return; return;
} }
track->_ssrc = pMediaSrc->getSsrc(track->_type); track->_ssrc = pMediaSrc->getSsrc(track->_type);
...@@ -773,11 +805,10 @@ void RtspSession::handleReq_Play(const Parser &parser) { ...@@ -773,11 +805,10 @@ void RtspSession::handleReq_Play(const Parser &parser) {
rtp_info << "url=" << _strContentBase << "/" << track->_control_surffix << ";" rtp_info << "url=" << _strContentBase << "/" << track->_control_surffix << ";"
<< "seq=" << track->_seq << ";" << "seq=" << track->_seq << ";"
<< "rtptime=" << (int)(track->_time_stamp * (track->_samplerate / 1000)) << ","; << "rtptime=" << (int) (track->_time_stamp * (track->_samplerate / 1000)) << ",";
} }
rtp_info.pop_back(); rtp_info.pop_back();
sendRtspResponse("200 OK", sendRtspResponse("200 OK",
{"Range", StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << (useBuf? pMediaSrc->getTimeStamp(TrackInvalid) / 1000.0 : iStartTime / 1000), {"Range", StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << (useBuf? pMediaSrc->getTimeStamp(TrackInvalid) / 1000.0 : iStartTime / 1000),
"RTP-Info",rtp_info "RTP-Info",rtp_info
...@@ -788,51 +819,24 @@ void RtspSession::handleReq_Play(const Parser &parser) { ...@@ -788,51 +819,24 @@ void RtspSession::handleReq_Play(const Parser &parser) {
if (!_pRtpReader && _rtpType != Rtsp::RTP_MULTICAST) { if (!_pRtpReader && _rtpType != Rtsp::RTP_MULTICAST) {
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this()); weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
_pRtpReader = pMediaSrc->getRing()->attach(getPoller(),useBuf); _pRtpReader = pMediaSrc->getRing()->attach(getPoller(), useBuf);
_pRtpReader->setDetachCB([weakSelf]() { _pRtpReader->setDetachCB([weakSelf]() {
auto strongSelf = weakSelf.lock(); auto strongSelf = weakSelf.lock();
if(!strongSelf) { if (!strongSelf) {
return; return;
} }
strongSelf->shutdown(SockException(Err_shutdown,"rtsp ring buffer detached")); strongSelf->shutdown(SockException(Err_shutdown, "rtsp ring buffer detached"));
}); });
_pRtpReader->setReadCB([weakSelf](const RtspMediaSource::RingDataType &pack) { _pRtpReader->setReadCB([weakSelf](const RtspMediaSource::RingDataType &pack) {
auto strongSelf = weakSelf.lock(); auto strongSelf = weakSelf.lock();
if(!strongSelf) { if (!strongSelf) {
return; return;
} }
if(strongSelf->_enableSendRtp) { if (strongSelf->_enableSendRtp) {
strongSelf->sendRtpPacket(pack); 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();
if(!strongSelf){
return;
}
onRes(err);
});
};
if(_bFirstPlay){
//第一次收到play命令,需要鉴权
auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed,_mediaInfo,invoker,static_cast<SockInfo &>(*this));
if(!flag){
//该事件无人监听,默认不鉴权
onRes("");
}
}else{
//后面是seek或恢复命令,不需要鉴权
onRes("");
}
} }
void RtspSession::handleReq_Pause(const Parser &parser) { void RtspSession::handleReq_Pause(const Parser &parser) {
......
...@@ -160,6 +160,8 @@ private: ...@@ -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: ...@@ -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播放器绑定的直播源
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论