使用gSOAP开发实例--Usernametoken Authentication实现
- 格式:docx
- 大小:57.18 KB
- 文档页数:20
authenticationmanager的authenticate方法(原创版3篇)篇1 目录1.AuthenticationManager 简介2.authenticate 方法的作用3.authenticate 方法的参数4.authenticate 方法的返回值5.authenticate 方法的实际应用篇1正文一、AuthenticationManager 简介AuthenticationManager 是 Java 中处理用户认证的一个接口,它负责管理与用户认证相关的操作。
在 Java 的安全模型中,AuthenticationManager 扮演着核心的角色,它允许我们实现自定义的认证逻辑,以满足不同场景下对安全性的需求。
二、authenticate 方法的作用AuthenticationManager 中的 authenticate 方法用于验证用户提供的身份凭据(如用户名和密码)是否与预期的凭据相匹配。
如果验证成功,该方法将返回一个 Authentication 对象,表示用户已成功登录;如果验证失败,则会抛出一个 AuthenticationException 异常。
三、authenticate 方法的参数authenticate 方法接收两个参数:ernamePasswordAuthenticationToken:这是用户提供的身份凭据,通常包括用户名和密码。
2.GrantedAuthority:这是一个可选参数,表示用户拥有的授权信息。
在实际应用中,我们可以利用这个参数为用户分配不同的权限。
四、authenticate 方法的返回值authenticate 方法的返回值是一个 Authentication 对象,它包含了用户认证的相关信息,如用户名、密码等。
如果验证失败,该方法将抛出一个 AuthenticationException 异常。
五、authenticate 方法的实际应用下面是一个使用 AuthenticationManager 的 authenticate 方法进行用户认证的简单示例:```javaimportorg.springframework.security.authentication.AuthenticationManag er;importernamePasswordAut henticationToken;importerDetails;importerDetailsServic e;importernameNotFoundE xception;public class CustomAuthenticationManager implements AuthenticationManager {private UserDetailsService userDetailsService;public CustomAuthenticationManager(UserDetailsService userDetailsService) {erDetailsService = userDetailsService;}@Overridepublic Authentication authenticate(AuthenticationToken token, GrantedAuthority authorities) throws AuthenticationException {String username = token.getName();String password = token.getPassword();try {UserDetails userDetails =erDetailsService.loadUserByUsername(username);if (userDetails == null||!userDetails.getPassword().equals(password)) {throw new UsernameNotFoundException("用户名或密码错误");}return new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());} catch (UsernameNotFoundException e) {throw new AuthenticationException("认证失败",e);}}}```在这个示例中,我们实现了一个自定义的 AuthenticationManager,它使用 UserDetailsService 来加载用户信息。
C++中gSOAP的使⽤详解⽬录SOAP简介gSOAP准备⼯作头⽂件构建客户端应⽤程序⽣成soap源码建⽴客户端项⽬构建服务端应⽤程序⽣成SOAP源码建⽴服务端项⽬打印报⽂SOAP测试项⽬源码总结本⽂主要介绍C++中gSOAP的使⽤⽅法,附带介绍SOAP协议的基础知识,适⽤于第⼀次使⽤gSOAP的开发⼈员。
gSOAP官⽹上的⽰例代码存在⼀些错误,对初次接触的⼈不太友好,本⽂是在官⽅⽰例的基础上进⾏了⼀些补充、改动。
SOAP简介SOAP 是⼀种简单的基于 XML 的协议,它使应⽤程序通过 HTTP 来交换信息,具体内容可以参考教程。
SOAP的本质是通过HTTP协议以XML格式进⾏数据交互,只不过这个XML格式的定义是⼤家公认的。
使⽤SOAP时需注意,SOAP的XML命名空间由于版本的不同可能存在差异(如soapevn、SOAP-ENV),在调⽤SOAP服务前最好确认服务器的XML格式。
gSOAPgSOAP 有商业版、开源版两个版本,开源版使⽤GPLv2开源协议,⽀持多个操作系统,具体内容参考或者。
gSOAP提供了⼀组编译⼯具(可以认为是代码⽣成器)和⼀些库⽂件,简化C/C++语⾔开发web服务或客户端程序的⼯作,开发⼈员可以专注于实现应⽤程序的逻辑:编译⼯具提供了⼀个SOAP/XML 关于C/C++ 语⾔的实现,能够⾃动完成本地C或C++数据类型和XML数据结构之间的转换。
库⽂件提供了SOAP报⽂⽣成、HTTP协议通讯的实现,及相关的配套设施,⽤于最终的SOAP报⽂的⽣成、传输。
本⽂使⽤的库⽂件主要是以下⼏个:stdsoap2.h、stdsoap2.cpp:HTTP协议的实现、最终的SOAP报⽂⽣成,如果是C语⾔则使⽤stdsoap2.h、stdsoap2.ctypemap.dat: wsdl2h⼯具根据wsdl⽂件⽣成头⽂件时需要此⽂件,可以更改项⽬的xml命名空间(后⾯再细说)threads.h:实现⾼性能的多线程服务器需要的⽂件,可以并发处理请求,并且在服务操作变得耗时时不会阻塞其他客户端请求准备⼯作先进⼊官⽹的,然后选择开源版本:将下载的压缩包解压(本⽂使⽤的是gsoap_2.8.117.zip),解压后的⽂件放到⾃⼰习惯的位置(推荐放到C盘)。
authenticationmanager 实例什么是AuthenticationManager?AuthenticationManager是Spring Security框架中的一个关键接口,用于处理用户身份验证。
它是Spring Security的身份验证机制的核心,负责验证用户提交的凭证,以确定用户是否能够访问受保护的资源。
AuthenticationManager接口定义了一个名为authenticate的方法,该方法接受一个Authentication对象作为参数,并返回一个完全填充和验证的Authentication对象。
AuthenticationManager接口通常由ProviderManager类的实例实现。
Authentication对象是Spring Security框架中的另一个核心接口,它代表了用户在系统中的身份。
Authentication对象包含了用户提交的凭证以及其他相关的信息,例如用户名、密码、权限等。
在认证过程中,AuthenticationManager会使用这些信息来验证用户的身份。
接下来,我们将一步一步地回答[authenticationmanager 实例]这个主题,介绍如何使用AuthenticationManager接口来实现身份验证。
第一步:导入所需的依赖首先,我们需要在项目中添加Spring Security的依赖。
可以通过Maven或Gradle来导入所需的依赖。
以下是一个Maven项目的示例pom.xml 文件,其中包含了我们需要的Spring Security依赖:xml<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId> </dependency></dependencies>当然,你可以根据自己的项目需求进行适当的调整。
基于gSOAP的WebService开发指导说明书1简介1.1目的本文通过给出gSOAP库的基本使用样例,帮助开发人员进行WebService相关的开发1.2范围本文只包含gSOAP库C++版本的基本使用样例,不包含其他高级使用或C版本的使用方式1.3名词解释1.4参考资料2准备工作2.1gSOAP库很显然,要想基于gSOAP库开发WebService应用,你需要首先获取gSOAP库。
gSOAP库是一个开源库,你可以在以下网址进行下载:/project/showfiles.php?group_id=52781如果链接失效,也可以去一个介绍gSOAP的网站上查看最新下载地址:/~engelen/soap.html本文所用的版本为(soapcpp2):下载下来以后解压缩,你会得到这么一个目录:其中gsoap目录有以下结构:注意这两个文件:stdsoap2.h和stdsoap2.cpp,我们编写gSOAP程序的时候是需要它们的。
还要注意的是bin\win32目录下的两个可执行文件:soapcpp2.exe和wsdl2h.exe,目前我们只需要soapcpp2.exe。
也就是说,要使用gSOAP,我们需三个文件:解压目录\gsoap-2.8\gsoap\ stdsoap2.h解压目录\gsoap-2.8\gsoap\ stdsoap2.cpp解压目录\gsoap-2.8\gsoap\bin\win32\ soapcpp2.exe使用gSOAP不需要在程序中添加额外的库,而是要通过工具生成并包含额外的文件。
接下来,我们通过一个实例去了解如何使用gSOAP提供的这三个文件。
3创建一个WebService服务端工程gSOAP使用了代码生成器帮助我们生成一些辅助性的框架与类,所以我们想要使用gSOAP,则需要做一些额外的工作。
下面我们就从零开始构建一个使用gSOAP的服务端工程。
3.1新建一个工程这一步没什么难度,使用VS直接新建一个工程即可。
gsoap中文文档8.1.2 关于命名空间函数ns1__getQuote(上节提到的)中,使用了ns1__作为远程方法的命名空间。
使用命名空间是为了防止远程方法名冲突,比方多个服务中使用同一个远程方法名的情况。
命名空间前缀及命名空间名称同时也被用来验证SOAP信息的内容有效性。
存根例程通过命名空间表中的信息来验证服务返回信息。
命名空间表在运行时被取出用于解析命名空间绑定,反序列化数据结构,解码并验证服务返回信息。
命名空间表不应该包含在gSOAP预编译器所需输入的头文件中。
在18.2节中将会对命名空间表做详细介绍。
Delayed Stock Quote服务客户端的命名空间表如下:struct Namespace namespaces[] ={ // {"命名前缀", "空间名称"}{"SOAP-ENV", "/soap/envelope/"}, // 必须是第一行{"SOAP-ENC", "/soap/encoding/"}, // 必须是第二行{"xsi", "/2001/XMLSchema-instance"}, // 必须是第三行{"xsd", "/2001/XMLSchema"}, // 2001 XML 大纲{"ns1", "urn:xmethods-delayed-quotes"}, // 通过服务描述获取{NULL, NULL} // 结束};第一行命名空间是SOAP1.1协议默认命名空间。
事实上,命名空间表就是用来让程序员可以规定SOAP编码方式,能够用包含命名空间的命名空间前缀来满足指定SOAP服务的命名空间需求的。
举例来说,使用前面命名空间表中定义的命名空间前缀ns1,存根例程就可以对getQuote方法的请求进行编码。
qt gsoap用法Qt gSOAP是一个在Qt框架下使用gSOAP工具包的库。
gSOAP可以通过使用Web服务定义语言(WSDL)生成SOAP服务端和客户端的代码。
在本篇文章中,我将介绍如何在Qt中使用gSOAP库。
首先,要在Qt项目中使用gSOAP,需要先安装gSOAP工具包。
可以在gSOAP官方网站上下载并安装最新版本的gSOAP。
安装完成后,打开Qt项目,将gSOAP的头文件和库文件添加到项目中。
可以通过以下步骤来实现:1. 在Qt Creator中打开项目,选择“项目”菜单,然后选择“属性”选项。
2. 在属性对话框中,选择“构建和运行”选项,然后选择“构建设置”选项卡。
3. 在"C++"部分中,选择“包含路径”选项,点击“添加”按钮,将gSOAP头文件所在的目录添加进来。
4. 在"链接器"部分中,选择“库路径”选项,点击“添加”按钮,将gSOAP库文件所在的目录添加进来。
5. 在"链接器"部分中,选择“附加库”选项,点击“添加”按钮,将gSOAP库文件添加进来。
完成上述步骤后,就可以在Qt项目中使用gSOAP了。
首先,我们需要编写一个WSDL文件来定义我们的SOAP服务。
可以使用gSOAP自带的wsdl2h工具来生成C++头文件。
在终端中运行以下命令:```shellwsdl2h -o HelloWorld.h HelloWorld.wsdl```这将生成一个名为HelloWorld.h的C++头文件,其中包含了定义我们的SOAP 服务所需的类和对象。
接下来,我们可以使用soapcpp2工具来生成主要的gSOAP源文件。
在终端中运行以下命令:```shellsoapcpp2 -i -C HelloWorld.h```这将生成一系列的C++源文件,其中包括用于编写我们的服务代码的skeleton 文件和stub文件。
现在,我们可以在Qt项目中创建一个新的类来实现我们的SOAP服务。
gsoap使用方法及心得(二)1、server端可以编译成CGI方式执行,而并不是绑定到某个端口。
if (argc < 2)// no args: assume this is a CGI application{soap_serve(&soap); // serve request, one thread, CGI stylesoap_destroy(&soap); // dealloc C++ datasoap_end(&soap); // dealloc data and clean up}2、在编译服务器及客户端程序时一开始把add.h生成的文件添加到工程,经常出现问题,需要自己调试。
特别是链接时段,server/client要与其生成的文件相对应,server调用生成的soapserver.cpp,client调用生成的soapclient.cpp文件。
3、多线程方式,在windows下建议用pthread_win32库,这里给出多线程下的例子。
(1) gSOAP需要的头文件://gsoap ns service name: calc//gsoap ns service style: rpc//gsoap ns service encoding: encoded//gsoap ns service namespace://gsoap ns service location://gsoap ns schema namespace: urn:calcint ns__add(double a, double b, double *result);int ns__sub(double a, double b, double *result);int ns__mul(double a, double b, double *result);int ns__div(double a, double b, double *result);int ns__pow(double a, double b, double *result);(2) 多线程服务器关键代码#include "calc.nsmap"#include "soapH.h"//宏与全局变量的定义#define BACKLOG (100)#define MAX_THR (10)#define MAX_QUEUE (1000)pthread_mutex_t queue_cs;//队列锁pthread_cond_t queue_cv;//条件变量SOAP_SOCKET queue[MAX_QUEUE];//数组队列int head =0, tail =0;//队列头队列尾初始化void * process_queue(void *);//线程入口函数int enqueue(SOAP_SOCKET);//入队列函数SOAP_SOCKET dequeue(void);//出队列函数//线程入口函数void * process_queue(void * soap){struct soap * tsoap = (struct soap *)soap;for(;;){tsoap->socket = dequeue();if (!soap_valid_socket(tsoap->socket)){break;}soap_serve(tsoap);soap_destroy(tsoap);soap_end(tsoap);}return NULL;}//入队列操作int enqueue(SOAP_SOCKET sock) {int status = SOAP_OK;int next;pthread_mutex_lock(&queue_cs); next = tail +1;if (next >= MAX_QUEUE){next = 0;}if (next == head){status = SOAP_EOM;}else{queue[tail] =sock;tail = next;}pthread_cond_signal(&queue_cv); pthread_mutex_unlock(&queue_cs); return status;}//出队列操作SOAP_SOCKET dequeue(){SOAP_SOCKET sock;pthread_mutex_lock(&queue_cs);while (head == tail ){pthread_cond_wait(&queue_cv,&queue_cs);}sock = queue[head++];if (head >= MAX_QUEUE){head =0;}pthread_mutex_unlock(&queue_cs);return sock;}//加法的实现int ns__add(struct soap *soap, double a, double b, double *result){*result = a + b;return SOAP_OK;}//减法的实现int ns__sub(struct soap *soap, double a, double b, double *result){*result = a - b;return SOAP_OK;}//乘法的实现int ns__mul(struct soap *soap, double a, double b, double *result){*result = a * b;return SOAP_OK;}//除法的实现int ns__div(struct soap *soap, double a, double b, double *result){if (b){*result = a / b;}else{char *s = (char*)soap_malloc(soap, 1024);sprintf(s, "Can't">/">Can't divide %f by %f", a, b);return soap_sender_fault(soap, "Division by zero", s);}return SOAP_OK;}//乘方的实现int ns__pow(struct soap *soap, double a, double b, double *result){*result = pow(a, b);if (soap_errno == EDOM) //oap_errno 和errorno类似, 但是和widnows兼容{char *s = (char*)soap_malloc(soap, 1024);sprintf(s, "Can't take the power of %f to %f", a, b);sprintf(s, "Can't">/">Can't take power of %f to %f", a, b);return soap_sender_fault(soap, "Power function domain error", s);}return SOAP_OK;}//主函数int main(int argc,char ** argv){struct soap ServerSoap;//初始话运行时环境soap_init(&ServerSoap);//如果没有参数,当作CGI程序处理if (argc <2){//CGI 风格服务请求,单线程soap_serve(&ServerSoap);//清除序列化的类的实例soap_destroy(&ServerSoap);//清除序列化的数据soap_end(&ServerSoap);}else{struct soap * soap_thr[MAX_THR];pthread_t tid[MAX_THR];int i,port = atoi(argv[1]);SOAP_SOCKET m,s;//锁和条件变量初始化pthread_mutex_init(&queue_cs,NULL);pthread_cond_init(&queue_cv,NULL);//绑定服务端口m = soap_bind(&ServerSoap,NULL,port,BACKLOG);//循环直至服务套接字合法while (!soap_valid_socket(m)){fprintf(stderr,"Bind port error! ");m = soap_bind(&ServerSoap,NULL,port,BACKLOG);}fprintf(stderr,"socket connection successful %d ",m);//生成服务线程for(i = 0; i <MAX_THR; i++){soap_thr[i] = soap_copy(&ServerSoap);fprintf(stderr,"Starting thread %d ",i);pthread_create(&tid[i],NULL,(void*(*)(void*))process_queue, (void*)soap_thr[i]);}for(;;){//接受客户端的连接s = soap_accept(&ServerSoap);if (!soap_valid_socket(s)){if (ServerSoap.errnum){soap_print_fault(&ServerSoap,stderr);continue;}else{fprintf(stderr,"Server timed out ");break;}}//客户端的IP地址fprintf(stderr,"Accepted connection from IP= %d.%d.%d.%d socket = %d ",((ServerSoap.ip)>>24)&&0xFF,((ServerSoap.ip)>>16)&0xFF,( (ServerSoap.ip)>>8)&0xFF,(ServerSoap.ip)&0xFF,(ServerSoap.so cket));//请求的套接字进入队列,如果队列已满则循环等待while(enqueue(s) == SOAP_EOM){Sleep(1000);}}//服务结束后的清理工作for(i = 0; i < MAX_THR; i++){while (enqueue(SOAP_INVALID_SOCKET) == SOAP_EOM){Sleep(1000);}}for(i=0; i< MAX_THR; i++){fprintf(stderr,"Waiting for thread %d to terminate ..",i);pthread_join(tid[i],NULL);fprintf(stderr,"terminated ");soap_done(soap_thr[i]);free(soap_thr[i]);}pthread_mutex_destroy(&queue_cs); pthread_cond_destroy(&queue_cv); }//分离运行时的环境soap_done(&ServerSoap);return 0;}。
gsoap使用小结gSoap使用小结分类:开发路上的点点滴滴 2012-03-30 11:33 3564人阅读评论(2) 收藏举报webservicesoapauthorizationnull工具c下载gSoap1.下载完成后直接解压缩,在目录gsoap-2.8\gsoap\bin下面有编译工具,支持多个平台,我们使用的是win32平台的工具wsdl2h.exe 解析WebService的wsdl文件soapcpp2.exe 编译WebService代码2.接下来需要先获得WebService的wsdl文件,访问WebService时,http://XXXX/XXXX.asmx?wsdl这个地址就是需要的wsdl文件,选择查看源文件,然后另存为的方式,获取到wsdl文件,例如:另存为webs.wsdl文件。
3.解析wsdl文件执行wsdl2h.exe -o webs.wsdl命令,就会生成一个webs.h的头文件这里简单说一下参数,主要常用的是-o和-c,-o后面跟的文件名是需要生成的文件名。
-c表示生成纯C的头文件,否则默认是C++。
具体参数可以运行wsdl2h.exe /?查看帮助。
4.编译执行soapcpp2.exe webs.h,会生成很多个文件,这里同样可以加一些参数,具体不解释了,可以通过soapcpp2.exe /?命令来查看。
我们找出需要的以下几个文件:soapC.cppsoapClient.cppsoapH.hsoapStub.hWebsSoap.nsmap再加上另外两个文件(不在bin目录下,在gsoap-2.8\gsoap目录下):stdsoap2.hstdsoap2.cpp一共7个文件,就是我们最终访问WebService所需要的soap访问调用文件。
这里是C++的代码,根据需要,也可以生成C的代码,stdsoap2.cpp更换为stdsoap2.h文件。
把上述7个文件,加入到自己的工程中编译即可,接下来就是如何调用的问题了。
gsoap用户手册gSOAP是一个用于开发Web服务和XML数据处理的开源工具包。
它支持多种编程语言,包括C和C++,并提供了丰富的功能和工具来简化Web服务的开发和集成。
gSOAP用户手册是一个详细的文档,涵盖了gSOAP工具包的安装、配置、使用和高级特性等方面的内容。
用户手册通常包括以下内容:1. 安装指南,用户手册会提供安装gSOAP工具包的详细步骤,包括下载源代码、编译安装和配置环境等内容。
这部分内容通常会针对不同的操作系统和开发环境进行说明。
2. 快速入门,用户手册会介绍如何快速上手使用gSOAP工具包,包括创建一个简单的Web服务、生成客户端代码、编译和部署等内容。
这部分内容通常会包括示例代码和详细的步骤说明。
3. gSOAP基础,用户手册会介绍gSOAP工具包的基本概念和核心功能,包括如何定义和发布Web服务、如何处理XML数据、如何进行SOAP通信等内容。
这部分内容通常会涵盖gSOAP工具包的核心API和使用方法。
4. 高级特性,用户手册会介绍gSOAP工具包的高级特性和扩展功能,包括如何处理安全性、如何进行性能优化、如何集成其他协议等内容。
这部分内容通常会提供一些实际的应用场景和最佳实践。
5. 参考资料,用户手册通常会包括一些附录和参考资料,如API参考、配置文件说明、常见问题解答等内容,以方便开发者查阅和深入理解gSOAP工具包。
总的来说,gSOAP用户手册是开发者学习和使用gSOAP工具包的重要参考资料,它提供了全面而详细的内容,帮助开发者快速上手并深入理解gSOAP工具包的各项功能和特性。
希望这些信息能够对你有所帮助。
7.4GSOAP工具的安装和使用7.4.1GSOAP安装GSOAP工具可以在WIN和UNIX两个系统平台下运行,这就使我们的程序在跨平台上有了基础。
工具的安装包可浏览其主页下载。
本DEMO的开发使用的版本为gsoap_win32_2.7.9l,工具的运行环境是Windows系统。
图7.12 Windows下的GSOAP安装包图7.13 LINUX或UNIX下的GSOAP安装包设置系统环境变量,这样可以很方便的使用GSOAP工具,如下为GSOAP的两个工具,我们将他们设置到可以在DOS下可直接使用的程序。
图7.14 GSOAP两个工具程序图7.15 GSOAP使用方法7.4.2生成客户端文件Wsdl2h.exe的参数说明参见7.5.1节图7.16 在DOS下使用wsdl2h.exe工具生成SendSMSClient.h文件图7.17 生成成功图7.18 生成的文件(短信为例)Soapcpp2.exe工具的参数说明参见7.5.2 节图7.19 根据.h生成客户端的文件图7.20 生成成功提示信息图7.21 生成的客户端文件表7.1 生成文件的说明其他文件在项目中没有使用,在此不做介绍,如需了解参看网络资料。
7.4.3生成服务端文件Wsdl2h.exe的参数说明参见7.5.1节图7.22 创建WEB SERVICE的.h文件图7.23 生成的文件Soapcpp2.exe工具的参数说明参见7.5.2 节图7.24 生成WEB SERVICE服务端文件图7.25 生成的服务端文件7.5GSOAP工具的参数soapcpp2.exe: gSOAP编译器,编译头文件生成服务器和客户端都需要的c/c++文件。
wsdl2h.exe: 编译wsdl文件生成c/c++头文件。
7.5.1wsdl2h.exe的使用wsdl2h是将wsdl定义转换成.h文件的工具。
主要有一些选项:-c代表转化成C代码。
-s代表不使用STL,取而代之需要在工程中包含stdsoap2.h和stdsoap2.cpp。
使用gSOAP开发实例——自定义header实现用户名令牌认证(Usernametoken Authentication)上一节介绍了怎样实现基本认证(Basic Authentication,以下简称basic方式),望文生义,也就是最简单的用户验证方式,本节稍微深入一些,介绍用户名令牌认证(Usernametoken Authentication,以下简称usernametoken方式)。
Usernametoken方式与basic方式不同的地方,在于后者会把用户名和密码以摘要(digest)的形式,置于HTTP信息头,而前者则把用户名以明文的形式、密码以明文或者摘要的形式,嵌入到一段XML文本中,再置于SOAP消息头当中。
如果使用soapUI调试客户端程序的话,会发现以下是basic方式发出的完整的SOAP消息:POST https:///Services/ECHO HTTP/0.9Content-Type: text/xml;charset=UTF-8SOAPAction: ""User-Agent: Jakarta Commons-HttpClient/3.1Content-Length: 292Authorization: Basic VkYtSEstbVNNST0OdlR42EMZaD1BMyE=Host: Cookie: $Version=0; MSP2LB=test2.test2f02; $Path=/<soapenv:Envelope xmlns:soapenv="/soap/envelope/"xmlns:echo="/ECHO"><soapenv:Header/><soapenv:Body><echo:echo><echo:EchoMessage>hello</echo:EchoMessage></echo:echo></soapenv:Body></soapenv:Envelope>以下是usernametoken方式发出的完整的SOAP消息:POST https:///4.0/services/SecureEcho HTTP/1.1Content-Type: text/xml;charset=UTF-8SOAPAction: ""User-Agent: Jakarta Commons-HttpClient/3.1Host: Content-Length: xxx<soapenv:Envelope xmlns:echo=""xmlns:soapenv="/soap/envelope/"><soapenv:Header><wsse:Security soapenv:mustUnderstand="1"xmlns:wsse="/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wsse:UsernameToken wsu:Id="UsernameToken-32870670"xmlns:wsu="/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><wsse:Username>roy</wsse:Username><wsse:PasswordType="/wss/2004/01/oasis-200401-wss-username-token-profile-1 .0#PasswordText">liang</wsse:Password><wsse:Nonce>LX4gh+njbEtCNAtkWkXDYA==</wsse:Nonce><wsu:Created>2010-08-11T06:02:25.874Z</wsu:Created></wsse:UsernameToken></wsse:Security><echo:customerId>G06164</echo:customerId></soapenv:Header><soapenv:Body><echo:sendEcho><echo:message>hello</echo:message></echo:sendEcho></soapenv:Body></soapenv:Envelope>其中,加粗部分表示两者的主要区别,红字部分表示各自必不可少的元素。
由此可以看出,usernametoken方式的特点,是在SOAP的header中加入一个Security标签,把usernametoken 信息放在这个Security标签里。
至于header里的另外一个customerId标签,是该应用自身的额外要求。
gSOAP实现basic方式相对简单,不过实现usernametoken就比较复杂。
gSOAP的用户指南推荐使用其自带的插件,在samples/wsse目录下的官方实例也是使用这个插件。
但是,我个人认为这种方法比较累赘,自动生成的代码太多,不易看懂,而且似乎非常依赖于wsdl本身的写法。
比如,samples/wsse目录下的官方实例含有下列表示SOAP header 的结构体,但是,在我实际开发的应用并没有自动产生,即使强行加上去,编译执行通过,运行的时候也出现了相当多的错误。
struct SOAP_ENV__Header{struct _wsse__Security *wsse__Security};而且,从理论上讲,gSOAP不过是一个框架,定义了从SOAP对象到SOAP消息,以及从SOAP消息到SOAP对象的序列化过程,并且提供了一套与之相适应的API,使用gSOAP开发不过是在其框架范围内调用其API编程。
框架的弊端,可想而知,限制了灵活,也限制了方便,更限制了创新。
所以,我们可以使用gSOAP编程,但是也许没有必要全部照搬,至少在这个案例中,就没有必要照搬。
我们应有的思路是,既然customerId可以直接写到SOAP header中,那么与之并列的、含有usernametoken的Security也可以直接写到SOAP header中,完全不需要依赖于gSOAP的wsse插件。
与上节一样,基于保密原则,本节案例采用的wsdl同样是经过裁剪和替换的,内容如下:<?xml version="1.0" encoding="UTF-8"?><wsdl:definitions targetNamespace="" xmln s:soapenc12="/2003/05/soap-encoding" xmlns:tns="http: //" xmlns:wsdl="/wsdl/ " xmlns:xsd="/2001/XMLSchema" xmlns:soap11="http://s /soap/envelope/" xmlns:wsdlsoap="http://schemas.xml /wsdl/soap/" xmlns:soapenc11="/soap /encoding/" xmlns:soap12="/2003/05/soap-envelope"> <wsdl:types><xsd:schema xmlns:xsd="/2001/XMLSchema" attributeF ormDefault="qualified" elementFormDefault="qualified" targetNamespace =""><xsd:element name="sendEcho"><xsd:complexType><xsd:sequence><xsd:element maxOccurs="1" minOccurs="1" name="message" type="xsd:s tring"/></xsd:sequence></xsd:complexType></xsd:element><xsd:element name="sendEchoResponse"><xsd:complexType><xsd:sequence><xsd:element maxOccurs="1" minOccurs="1" name="out" type="xsd:strin g"/></xsd:sequence></xsd:complexType></xsd:element><xsd:element name="showVersionInformation"><xsd:complexType/></xsd:element><xsd:element name="showVersionInformationResponse"><xsd:complexType><xsd:sequence><xsd:element maxOccurs="1" minOccurs="1" name="out" type="xsd:strin g"/></xsd:sequence></xsd:complexType></xsd:element><xsd:element name="customerId" type="xsd:string"/></xsd:schema></wsdl:types><wsdl:message name="sendEchoRequestHeaders"><wsdl:part name="customerId" element="tns:customerId"></wsdl:part></wsdl:message><wsdl:message name="showVersionInformationRequestHeaders"> <wsdl:part name="customerId" element="tns:customerId"></wsdl:part></wsdl:message><wsdl:message name="sendEchoResponse"><wsdl:part name="parameters" element="tns:sendEchoResponse"></wsdl:part></wsdl:message><wsdl:message name="showVersionInformationRequest"><wsdl:part name="parameters" element="tns:showVersionInformation"></wsdl:part></wsdl:message><wsdl:message name="sendEchoRequest"><wsdl:part name="parameters" element="tns:sendEcho"></wsdl:part></wsdl:message><wsdl:message name="showVersionInformationResponse"><wsdl:part name="parameters" element="tns:showVersionInformatio nResponse"></wsdl:part></wsdl:message><wsdl:portType name="SecureEcho"><wsdl:operation name="sendEcho"><wsdl:input name="sendEchoRequest" message="tns:sendEchoReque st"></wsdl:input><wsdl:output name="sendEchoResponse" message="tns:sendEchoRes ponse"></wsdl:output></wsdl:operation><wsdl:operation name="showVersionInformation"><wsdl:input name="showVersionInformationRequest" message="tns: showVersionInformationRequest"></wsdl:input><wsdl:output name="showVersionInformationResponse" message="t ns:showVersionInformationResponse"></wsdl:output></wsdl:operation></wsdl:portType><wsdl:binding name="SecureEchoHttpBinding" type="tns:SecureEcho"> <wsdlsoap:binding style="document" transport="http://schemas.xm /soap/http"/><wsdl:operation name="sendEcho"><wsdlsoap:operation soapAction=""/><wsdl:input name="sendEchoRequest"><wsdlsoap:body use="literal"/><wsdlsoap:header message="tns:sendEchoRequestHeaders" part= "customerId" use="literal"></wsdlsoap:header></wsdl:input><wsdl:output name="sendEchoResponse"><wsdlsoap:body use="literal"/></wsdl:output></wsdl:operation><wsdl:operation name="showVersionInformation"><wsdlsoap:operation soapAction=""/><wsdl:input name="showVersionInformationRequest"><wsdlsoap:body use="literal"/><wsdlsoap:header message="tns:showVersionInformationRequest Headers" part="customerId" use="literal"></wsdlsoap:header></wsdl:input><wsdl:output name="showVersionInformationResponse"><wsdlsoap:body use="literal"/></wsdl:output></wsdl:operation></wsdl:binding><wsdl:service name="SecureEcho"><wsdl:port name="SecureEchoHttpPort" binding="tns:SecureEchoHttpBinding"><wsdlsoap:address location="https://localhost:6883"/> </wsdl:port></wsdl:service></wsdl:definitions>在gSOAP的wsdl目录,按以下步骤建立客户端存根程序:-bash-3.2$ mkdir –p secure_echo-bash-3.2$ cd secure_echo-bash-3.2$ ../wsdl2h –c –o secure_echo.h secure_echo.wsdl-bash-3.2$ ../../src/soapcpp2 –C –L –x secure_echo.h重点来了,此时需要修改gSOAP为你自动生成的部分文件,加入usernametoken支持,以下是详细步骤,代码中加粗部分即修改的内容:1. soapStub.h,搜索SOAP_ENV__Header结构体,本案例中,gSOAP只为我们自动生成了对应customerId 的指针,因为需要在SOAP header中增加用户名和密码,所以要在这里手动添加这些信息。