首先我们讨论一下sip服务器回复401与407有什么区别,看了一下rfc3261,发现没有明确的说明,只是说401是UAS和registar回复的应答,而407是proxy回复的应答。但是很多时候proxy就是UAS,在GB28181里面有什么讲究呢?从网络上看到这么一种解答不知准确与否:
401 Unauthorized,明确提示是未授权。这个应答是由UAS和注册服务器产生的。常见场景是Register用户注册的时候。
407 proxy authentication required ,意思是proxy服务器需要提供认证信息。常见场景是Invite发起呼叫的时候。
目前我们就当他是准确的说法吧,回到我们的问题,怎么解决服务器对registration回复是407而不是401,通过跟踪源码我们发现:
SipMessage*
Helper::makeChallenge(const SipMessage& request, const Data& realm, bool useAuth, bool stale, bool proxy)
{
Auth auth;
auth.scheme() = Symbols::Digest;
Data timestamp(Timer::getTimeSecs());
auth.param(p_nonce) = makeNonce(request, timestamp);
auth.param(p_algorithm) = "MD5";
auth.param(p_realm) = realm;
if (useAuth)
{
auth.param(p_qopOptions) = "auth,auth-int";
}
if (stale)
{
auth.param(p_stale) = "true";
}
SipMessage *response;
if(proxy)
{
response = Helper::makeResponse(request, 407);
response->header(h_ProxyAuthenticates).push_back(auth);
}
else
{
response = Helper::makeResponse(request, 401);
response->header(h_WWWAuthenticates).push_back(auth);
}
return response;
}
我们Helper是根据是否是proxy决定生成401的响应还是407的响应,如果是proxy生成407,如果不是生成401.
而是不是proxy是由ServerAuthManager决定的,调用上面代码的代码片段为:
void
ServerAuthManager::issueChallenge(SipMessage *sipMsg)
{
//assume TransactionUser has matched/repaired a realm
SharedPtr<SipMessage> challenge(Helper::makeChallenge(*sipMsg,
getChallengeRealm(*sipMsg),
useAuthInt(),
false /*stale*/,
proxyAuthenticationMode()));
InfoLog (<< "Sending challenge to " << sipMsg->brief());
mDum.send(challenge);
}
而在ServerAuthManager中proxyAuthenticationMode()的返回值总为true,所以我们得想办法让该函数的返回值为false,本着不改变协议栈代码的原则,我们发现proxyAuthenticationMode()是一个虚函数,所以我们只要写一个类继承ServerAuthManager,在我们的新类中将proxyAuthenticationMode()的返回值改为false即可解决该问题。