ONVIF 自定义soap结构体实现用户认证

来源:互联网 发布:用矩阵解决实际问题 编辑:程序博客网 时间:2024/05/15 23:43
</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 64struct 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 Addsize_t  soap_flag_auth = 1;//Michael Add//Michael Addif ( 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 Addint 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 Add

3  得到用户名密码等信息后,校验
在每条指令调用的函数,都携带了 struct soap ×的结构体指针,获取出来之后,就可以,使用 SHA1 算法进行密码校验了。具体算法请参考ONVIF 编程手册[ONVIF_WG-APG-Application_Programmer's_Guide] ,这个文档可以从ONVIF官方下载。


需要使用 SHA1 算法,请参考我的博客文章,有SHA1的实现。base64算法在gSOAP代码里面可以找到。

继续在 struct soap结构体里定义回调函数,完成用户认证应该困难不大了。



0 0