如何使用使用自定义用户名验证和 PHP 页面的 WCF Web 服务?

Posted

技术标签:

【中文标题】如何使用使用自定义用户名验证和 PHP 页面的 WCF Web 服务?【英文标题】:How to consume a WCF Web Service that uses custom username validation with a PHP page? 【发布时间】:2011-10-02 21:26:06 【问题描述】:

我很难从 php 站点使用安全的 WCF Web 服务。我对 PHP 的了解有限,我在网上找到了各种示例,但还没有成功。

我有一个 Silverlight 应用程序,它也使用这个 WebService,它工作正常。但是当我运行 PHP 站点时,我得到了这个错误:

MessageSecurityException:安全处理器无法在消息中找到安全标头。这可能是因为消息是不安全的错误,或者是因为通信双方之间存在绑定不匹配。如果服务配置了安全性并且客户端未使用安全性,则可能会发生这种情况。

我还尝试将 customBinding 更改为 basicHttpBinding。当我这样做时,不再调用自定义用户名验证器。但是,在我的 WCF 服务上使用 basicHttpBinding 并删除凭据验证“有效”(除了它不安全的事实之外)。所以问题似乎与安全消息有关。

谁能给我一个可以帮助我使这个 PHP 页面正常工作的工作示例或教程?

这是我的 PHP 代码:

    $options = array( 
            'soap_version'  => SOAP_1_1, 
            'exceptions'    => true, 
            'trace'         => 1, 
            'cache_wsdl'    => WSDL_CACHE_NONE,
            'Username'      => 'MyUserName', 
            'password'      => 'MyPassword');

$client = new SoapClient('https://UrlToService/Service.svc?wsdl', $options); 

try

    $phpresponse = $client->Get(); 

    print $phpresponse->GetResult->Version;
    echo "</b><BR/><BR/>";

catch(Exception $e) 
 
    echo "<h2>Exception Error!</h2></b>"; 
    echo $e->getMessage(); 
    echo "<BR/><BR/>";

WCF 配置

<behavior name="sslBehavior">
   <serviceMetadata httpsGetEnabled="true" />
   <serviceDebug includeExceptionDetailInFaults="true" />
   <serviceCredentials>
      <userNameAuthentication userNamePasswordValidationMode="Custom"   customUserNamePasswordValidatorType="MyNamespace.ServiceUserNameValidator, MyNamespace" />
   </serviceCredentials>
   <serviceSecurityAudit
    auditLogLocation="Application"
    serviceAuthorizationAuditLevel="Failure"
    messageAuthenticationAuditLevel="Failure"
    suppressAuditFailure="true" />
</behavior>

<customBinding>
    <binding name="sslCustomBinding">
      <security authenticationMode="UserNameOverTransport" includeTimestamp="true" allowInsecureTransport="true">
        <localServiceSettings maxClockSkew="00:10:00" />
        <localClientSettings maxClockSkew="00:10:00" />
        <secureConversationBootstrap />
      </security>
      <textMessageEncoding messageVersion="Soap11" />
      <httpsTransport />
    </binding>
  </customBinding>

<service behaviorConfiguration="sslBehavior" name="MyNamespace.Services.Service">
    <endpoint address="" binding="customBinding" 
              bindingConfiguration="sslCustomBinding" contract="MyNamespace.ServiceContracts.IService" />
    <host>
      <baseAddresses>
        <add baseAddress="https://UrlToService/Services/" />
      </baseAddresses>
    </host>
  </service>

【问题讨论】:

【参考方案1】:

我解决了这个问题。我不得不在 PHP 中扩展“SoapHeader”类以使其符合 WS-Security 标准。

解决办法如下:

PHP Header 类

class WsseAuthHeader extends SoapHeader 

    private $wss_ns = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd';
    function __construct($user, $pass, $ns = null) 
        
        if ($ns) 
                
            $this->wss_ns = $ns;    
            

        $auth = new stdClass();    

        $auth->Username = new SoapVar($user, XSD_STRING, NULL, $this->wss_ns, NULL, $this->wss_ns);     
        $auth->Password = new SoapVar($pass, XSD_STRING, NULL, $this->wss_ns, NULL, $this->wss_ns);    
        $username_token = new stdClass();    
        $username_token->UsernameToken = new SoapVar($auth, SOAP_ENC_OBJECT, NULL, $this->wss_ns, 'UsernameToken', $this->wss_ns);     
        $security_sv = new SoapVar(        
                                new SoapVar($username_token, SOAP_ENC_OBJECT, NULL, $this->wss_ns, 'UsernameToken', $this->wss_ns),        
                                SOAP_ENC_OBJECT, NULL, $this->wss_ns, 'Security', $this->wss_ns);    

        parent::__construct($this->wss_ns, 'Security', $security_sv, true);
    

PHP 客户端调用

$options = array( 
            'soap_version'    => SOAP_1_1, 
            'exceptions'      => true, 
            'trace'           => 1, 
            'wdsl_local_copy' => true
            );


$username = "MyUser";
$password = "MyPassword";

$wsse_header = new WsseAuthHeader($username, $password);    

$client = new SoapClient('https://UrlToService/Service.svc?wsdl', $options); 
$client->__setSoapHeaders(array($wsse_header));

try

    $phpresponse = $client->Get(); 

    print $phpresponse->GetResult->Version;
    echo "</b><BR/><BR/>";

catch(Exception $e) 
 
    echo "<h2>Exception Error!</h2></b>"; 
    echo $e->getMessage(); 

希望对其他人有所帮助!

感谢克里斯:Connecting to WS-Security protected Web Service with PHP

【讨论】:

是的,它帮助了我! 这对我也有帮助!很好的解决方案!【参考方案2】:

SOAP 的身份验证有点有趣(或者可以),我使用了来自 http://www.php.net/manual/en/soapclient.soapclient.php#101503 的方法,请参阅来自 faebu 在 faebu dot ch 21-Dec-2010 02:58 的评论,因为这样做了几次.. . 它可能会有所帮助

基本上使用 CURL 来传递身份验证凭据...它可能/可能不适合您!

【讨论】:

我刚刚尝试过,但不幸的是,它不起作用。我看到正在创建 xml,但我仍然收到相同的异常。

以上是关于如何使用使用自定义用户名验证和 PHP 页面的 WCF Web 服务?的主要内容,如果未能解决你的问题,请参考以下文章

在规则中使用 php 会话值进行自定义 jquery 验证

SpringBoot Security 整合thymeleaf模板自定义登录页面,按需提示错误信息

Spring Security 4 2FA

如何在 Spring Security 中通过 jdbc 身份验证使用自定义登录页面

如何使用 Spring Security 自定义登录页面?

jQuery 验证器和使用 AJAX 的自定义规则