</pre><p>ONVIF 用户校验实现</p><p><span style="white-space:pre"> </span>ONVIF 开发使用C/C++的话,使用 gsoap 这个工具是好用的。直接生成代码框架。以下是使用 gSOAP 自己修改框架完成用户认证的方法,</p><p><ol><li>gSOAP 生成的代码框架,在stdsoap2.c 文件的 struct SOAP_STD_API soap { ... } 结构体里面添加一个结构体 struct WS_UsernameToken SUsernameToken; 用来保存每条指令传过来的用户名,密码校验等信息。</li></ol></p><p></p><pre name="code" class="cpp">#define AUTHENTICATION_NAME_LEN 64
struct WS_UsernameToken
{
char m_acSoapUsername[AUTHENTICATION_NAME_LEN];
char m_acSoapPassword[AUTHENTICATION_NAME_LEN];
char m_acSoapPasswordType[AUTHENTICATION_NAME_LEN*2];
char m_acSoapNonce[AUTHENTICATION_NAME_LEN];
char m_acSoapCreated[AUTHENTICATION_NAME_LEN];
};
因为gSOAP生成的代码框架,每条请求都携带一个 struct soap * 指针,所以把结构体存在这个 结构很合理。回调函数指针也应该存储在这个结构体。
2. 从请求指令里获取客户端传过来的用户名密码等信息
soapC.c 文件的 soap_in_SOAP_ENV__Header() 这个函数 (这个函数是gSOAP生成),是请求消息头域分析函数,从这里可以得到ONVIF定义的SOAP头域的所有字段。
仿照 soap_in_SOAP_ENV__Header() 函数内部的写法,添加以下代码,获取用户名密码头域。
//Michael Add
size_t soap_flag_auth = 1;
//Michael Add
//Michael Add
if ( soap_flag_auth && (soap->error == SOAP_TAG_MISMATCH || soap->error == SOAP_NO_TAG )
{
if ( soap_in_PointerTo_Authentication(soap) == 0 )
{
soap_flag_auth--;
continue;
}
}
//Michael Add
soap_in_PointerTo_Authentication()这个函数也是仿照 gSOAP 生成框架的代码格式编写的,如下:
//Michael Add
int soap_in_PointerTo_Password(struct soap *soap,char **password,char **passwordType)
{
//if (soap_element_begin_in(soap,"wsse:Password",1,NULL))
// return 1;
if (soap_s2string(soap,soap_attr_value(soap,"Type",0),passwordType,0,-1))
return 1;
if (!soap_in_string(soap,"wsse:Password",password,"xsd:string"))
return 1;
//Type http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest
//if ( soap_element_end_in(soap,"wsse:Password") )
// return 1;
return SOAP_OK;
}int soap_in_PointerTo_Authentication(struct soap *soap)
{
size_t soap_flag_Username = 1;
size_t soap_flag_Password = 1;
size_t soap_flag_Nonce = 1;
size_t soap_flag_wsu__Created = 1;
char *username = NULL ;
char *password = NULL ;
char *passwordType = NULL ;
char *nonce = NULL;
char *created = NULL;
struct WS_UsernameToken UsernameToken;
memset(&UsernameToken,0,sizeof(struct WS_UsernameToken));
if (soap_element_begin_in(soap, "wsse:Security", 1, NULL) != 0 )
return 1;
if ( soap_element_begin_in(soap,"wsse:UsernameToken",1,NULL) != 0 )
return 1;
for(;;)
{
soap->error = SOAP_TAG_MISMATCH;
if ( soap_flag_Username && (soap->error == SOAP_TAG_MISMATCH || soap->error == SOAP_NO_TAG ))
if ( soap_in_string(soap,"wsse:Username",&username,"xsd:string") )
{
soap_flag_Username-- ;
continue;
}
if (soap_flag_Password && (soap->error == SOAP_TAG_MISMATCH || soap->error == SOAP_NO_TAG ) )
//if ( soap_in_string(soap,"wsse:Password",&password,"xsd:string") )
if( soap_in_PointerTo_Password(soap,&password,&passwordType))
{
soap_flag_Password-- ;
continue;
}
if (soap_flag_Nonce && (soap->error == SOAP_TAG_MISMATCH || soap->error == SOAP_NO_TAG ) )
if ( soap_in_string(soap,"wsse:Nonce",&nonce,"xsd:string") )
{
soap_flag_Nonce-- ;
continue;
}
if (soap_flag_wsu__Created && (soap->error == SOAP_TAG_MISMATCH || soap->error == SOAP_NO_TAG ) )
if ( soap_in_string(soap,"wsu:Created",&created,"xsd:string") )
{
soap_flag_wsu__Created-- ;
continue;
}
if (soap->error == SOAP_TAG_MISMATCH)
soap->error = soap_ignore_element(soap);
if (soap->error == SOAP_NO_TAG)
break;
if (soap->error)
return 1;
}
soap_element_end_in(soap, "wsse:UsernameToken");
soap_element_end_in(soap, "wsse:Security");
memset(soap->SUsernameToken.m_acSoapUsername,0,AUTHENTICATION_NAME_LEN);
memset(soap->SUsernameToken.m_acSoapPassword,0,AUTHENTICATION_NAME_LEN);
memset(soap->SUsernameToken.m_acSoapPasswordType,0,AUTHENTICATION_NAME_LEN*2);
memset(soap->SUsernameToken.m_acSoapCreated,0,AUTHENTICATION_NAME_LEN);
memset(soap->SUsernameToken.m_acSoapNonce,0,AUTHENTICATION_NAME_LEN);
if ( username != NULL )
{
strcpy(soap->SUsernameToken.m_acSoapUsername,username);
}
if ( password != NULL )
{
strcpy(soap->SUsernameToken.m_acSoapPassword,password);
}
if ( passwordType != NULL )
{
strcpy(soap->SUsernameToken.m_acSoapPasswordType,passwordType);
}
if ( created != NULL )
{
strcpy(soap->SUsernameToken.m_acSoapCreated,created);
}
if ( nonce != NULL )
{
strcpy(soap->SUsernameToken.m_acSoapNonce,nonce);
}
return SOAP_OK;
}
//Michael Add3 得到用户名密码等信息后,校验
在每条指令调用的函数,都携带了 struct soap ×的结构体指针,获取出来之后,就可以,使用 SHA1 算法进行密码校验了。具体算法请参考ONVIF 编程手册[ONVIF_WG-APG-Application_Programmer's_Guide] ,这个文档可以从ONVIF官方下载。
需要使用 SHA1 算法,请参考我的博客文章,有SHA1的实现。base64算法在gSOAP代码里面可以找到。
继续在 struct soap结构体里定义回调函数,完成用户认证应该困难不大了。
900



被折叠的 条评论
为什么被折叠?



