onvif gsoap鉴权最佳实践

xingyun86 2021-1-21 2060

onvif 鉴权最佳实践

上一篇文章》讲了如何gsoap生成代码。但是生成以后使用时还有一些问题要注意。如鉴权:常用的有WS-Username_token、Digest鉴权.

wsseapi.h里面默认包含了WS-Username_token鉴权方式,使用比较简单

重点说下Digest鉴权方式:

需要用到httpda.h,httpda.c文件引入项目。原理是:

1.先请求获取认证序列号及相关参数

2.填入用户名密码进行Digest验证

与WS-Username_token不同的地方是:在HTTP协议认证选项中填写认证参数。而后者则是在XML节点(报文体)中填写认证参数

完整鉴权代码:

T -- 业务逻辑代理类
T1 -- 请求参数类
T2 -- 对应请求参数的应答类
call -- T的成员函数(参数1为T1指针,参数2为T2引用)

template <class T, class T1, class T2>
    int BindingRequest(T* t, T1* t1, T2& t2, int (T::* call)(T1*, T2&), const std::string& hostname, const std::string& userid, const std::string& passwd) {
        t->soap_endpoint = hostname.c_str();
        if (SOAP_OK == soap_wsse_add_UsernameTokenDigest(t->soap, nullptr, userid.c_str(), passwd.c_str())) {
            if (SOAP_OK != (t->*call)(t1, t2)) {
                if (t->soap->status == 400) {
                    //WS-Username Token鉴权失败,转入Digest鉴权
                    soap_register_plugin(t->soap, http_da);
                    if (SOAP_OK != (t->*call)(t1, t2)) {
                        if (t->soap->status == 401)
                        {
                            //首次Digest鉴权返回401是正常的,此时可以获取到Digest的几个参数项,此时再填写用户名和密码,进行二次请求
                            struct http_da_info httpDaInfo = { 0 }; // to store userid and passwd
                            //soap.authrealm在验证失败从服务器返回
                            http_da_save(t->soap, &httpDaInfo, t->soap->authrealm, userid.c_str(), passwd.c_str());
                            if (SOAP_OK != (t->*call)(t1, t2)) {
                                std::cerr << "Oops, something went wrong:" << std::endl;
                                soap_stream_fault(t->soap, std::cerr);
                            }
                            http_da_restore(t->soap, &httpDaInfo);
                            http_da_release(t->soap, &httpDaInfo);
                        }
                    }
                }
            }
        }
        return t->soap->status;
    }

使用案例:

void cleanup_soap(struct soap* soap) {
    if (soap != nullptr) {
        soap_destroy(soap);
        soap_end(soap);
        soap_free(soap);
    }
}
//获取设备信息
void getDeviceInformation() {
        DeviceBindingProxy proxy(soap_new());
        _tds__GetDeviceInformation GetDeviceInfo = {};
        _tds__GetDeviceInformationResponse GetDeviceInformationResponse = {};
        BindingRequest<DeviceBindingProxy, _tds__GetDeviceInformation, _tds__GetDeviceInformationResponse>(
            &proxy, &GetDeviceInfo, GetDeviceInformationResponse, &DeviceBindingProxy::GetDeviceInformation, hostname, username, password);
        if (proxy.soap->status == 200)
        {
            std::cout << "Manufacturer:    " << GetDeviceInformationResponse.Manufacturer << std::endl;
            std::cout << "Model:           " << GetDeviceInformationResponse.Model << std::endl;
            std::cout << "FirmwareVersion: " << GetDeviceInformationResponse.FirmwareVersion << std::endl;
            std::cout << "SerialNumber:    " << GetDeviceInformationResponse.SerialNumber << std::endl;
            std::cout << "HardwareId:      " << GetDeviceInformationResponse.HardwareId << std::endl;
        }
        cleanup_soap(proxy.soap);
    }


×
打赏作者
最新回复 (0)
查看全部
全部楼主
返回