php soap 身份验证
php+soap身份验证2011-07-17 08:43php soap编码转换
在给CHINAZ资讯(dedecms)做同步bbsmax passport登陆api时,因为bbsmax使用utf-8编码,而资讯这边用的是GBK编码,导致乱码。开始想自己转码,但有点麻烦。后面想SOAP既然用来针对不同平台,那肯定也包括编码问题,就又认真看了PHP手册,介绍里虽然没有提到,却发现Examples里有,访问很简单。
$client=new SoapClient("some.wsdl",array'encoding'='GBK'
只要这么简单,剩下的PHP自己帮忙实现了~
通过SoapHeader实现身份认证
之前一直抱怨php的soap很傻,在client端有设置header的方法,在server端却没有取header的方法。那是很傻很天真,直接用正则
达式从soap信封的header中提取header信息。
最近由于有项目要发布webservice,重新燃起对soap的兴趣,看了w3的英文文档,那是个云里雾里。收集了一些资料,做了一个关于saop header进行身份认证的实验。
在这个实验中,假定soap client用一个字符串作为身份认证的标识,soap server取到这个字符串后,对其进行辨认,如果与期望相符合,认证通过,如果不符,抛出soapFault。
理论就不多说了,我也不懂,直接上代码
client.php
?php
$cli=new SoapClient(null,array('uri'=''location'=''trace'=true));
$h=new SoapHeader(''auth','123456789',false,SOAP_ACTOR_NEXT);
$cli-__setSoapHeaders(array($h)); try{
; echo$cli-say()
}catch(Exception$e){ echo$e-getMessage();
}
server.php
?php class Server{ public function auth($a) {
if($a~='123456789'){ throw new SoapFault('Server','您无权访问'); }
}
function say()
{
return'Hi';
}
}
$srv=new SoapServer(null,array('uri'='setClass('Server');
$srv-handle();
以上代码就实现了认证的功能,最关键的地方就是SoapHeader的构造。soapHeader有五个构造参数,
Namespace无用
Name鉴别身份标识的函数或者方法名
Data存放标识身份的字符串
mustUnderstand是否必须处理该header actor处理该header的角色(不是太理解)
红色的一行,构造了一个soapHeader,header的名称为"auth",data为"123456789",mustUnderstand为false,actor为SOAP_ACTOR_NEXT。
注意观察server.php中的server类有一个方法"auth",刚好与header的名称对应,方法auth的参数$u,就是soapHeader的data,soapServer接收到这个请求会,先调用auth方法,并把"123456789"作为参数传递给该方法。
mustUnderstand参数为false时,即便没有auth这个方法,say方法也会被调用,但是如果它为true的话,如果auth方法不存在,就会返回一个Soapfault告知该header没有被处理。
actor参数指名那些role必须处理该header,这儿我理解得不是太透彻,不好说。
大概就这样,关键点在于SoapHeader的构造。
soap官方:转使用SoapHeader实现Soap请求验证
在PHP的Soap Extension中,对于SoapServer来说,并没有方法可用得到/处理客户端发送的SoapHeader信息.
网上也有很多人认为,只能通过读取POST过来的请求XML文件,
,才能得到客户端发送过来的SoapHeader.但,其实在SoapServer端,其实是有一种办法,可用把SoapHeader当作一个请求来处理,从而获取到客户端提交的SoapHeader信息.
假设客户端代码如下
?php
/*
*保存用户名和密码的载体
*/
class SoapUserInfo{
/*
*@var char$name
*/
public$name;
/*
*@var char$password
*/
public$password;
public function __construct($l,$p){
$this-Password=$p;
$this-Username=$l;
}
}
?
然后客户端生成SoapHeader
?php
$soap_header=new SoapHeader("'Authorise'
,new SoapUserInfo('laruence','password'),false,SOAP_ACTOR_NEXT);
?
也许细心的同学会注意到第4个参数FALSE和第5个参数
SOAP_ACTOR_NEXT,这是什么呢?我最后再讲.
然后,创建客户端,绑定SoapHeader ?php
$client=new SoapClient($wsdl);
$client-__setSoapHeaders(array($soap_header)); $client-__soapCall('request',array()); ?
现在,客户端已经发起了请求,请求中也包含了SoapHeader,其中有了我们
验证需要的用户名/密码信息.
那么,在服务端,该如何做呢?
?php
$server=new SoapServer('laruence.wsdl');
-setClass('InterfaceClass'); $server
$server-handle();
?
关键的地方就在,服务端接收请求以后,会实例化一个处理类,然后分析SoapHeader,接着就会调用InterfaceClass:Authorise这个方法(Authorise是我们请求头中的变量名),所以,我们就可用在InterfaceClass类中,定义个Authorise方法,并在这个方法中对SoapHeader中的信息做验证.
然后,请求体(Soap body)中的方法被调用,因为不论Authorise方法返回什么除非exit),请求体中的方法一定会被调用,所以要寻找个变量记录验证的结果.
?php class InterfaceClass{
/*
*@var bool$authorized
*/
private$authorized=FALSE;
/*
*Authentication function
*
*@param string username *@param string password */
blic function Authentication($username,$password){ pu
$this-authorized=validateUser($username,$password); }
/*
*Test method
*/
public function request(){ if($this-authorized){ //验证成功,继续处理.
}else{
//验证失败,拒绝请求.
}
}
}
?
当然,对于网上说的另外一种方法,通过分析请求的XML文件,也可以
?php class InterfaceClass{ /*
*@var bool$authorized
*/
private$authorized=FALSE;
function __construct(){
$xml=file_get_contents('php://input');
//分析xml,获得SoapHeader数据,验证
}
}
?
Must Understand
这个参数指明了,是否服务端必须要了解SoapHeader,如果这个参数为真,
而服务端并不能识别响应的Header,则会引发一个Soap Fault(Header not
understood).
SOAP_ACTOR_NEXT actor指明了SoapHeader要传递给谁,被谁处理. SOAP_ACTOR_NEXT的意思就是,下一个接受到这个请求头的Service,在本文
的例子中只有一个Server,当然也就没有关系了.
在SoapServer的构造函数中,我们可以指明一个Server的Actor,比如 ?php
$server=new SoapServer($wsdl,array('actor'='laruence'));
?
这样,我们就可以在Client的SoapHeader中,通过设置actor是laruence,
来让指定的Server来获得我们设置的头部的信息.