WCF: Impossibile trovare il mio validatore personalizzato specificato in web.config - customUserNamePasswordValidatorType - - Impossibile caricare il file o l'assembly & # 8230; - Aiuto?
-
05-07-2019 - |
Domanda
Quindi ho praticamente tutto funzionato con wsHttpBindings e il mio servizio WCF usando l'autenticazione personalizzata su HTTPS.
Il problema che sto riscontrando riguarda customUserNamePasswordValidatorType:
<serviceCredentials>
<!-- Use our own custom validation -->
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="CustomValidator.CustomUserNameValidator, CustomValidator"/>
</serviceCredentials>
Trovate le seguenti indicazioni qui I ho creato anche la mia classe personalizzata:
namespace CustomValidator
{
public class CustomUserNameValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (null == userName || null == password)
{
throw new ArgumentNullException();
}
if (!AuthenticateUser(userName, password))
throw new SecurityTokenValidationException("Invalid Credentials");
L'errore è " Impossibile caricare il file '' CustomValidator '' o una delle sue dipendenze. Il sistema non è in grado di trovare il file specificato. " ;, e fa riferimento alla fine del customUserNamePasswordValidatorType - " ..., CustomValidator " ;.
Non pensavo che fosse un problema avere il mio validatore personalizzato nel suo spazio dei nomi e classe, ma non riesco a vedere cos'altro fare per farlo funzionare.
Ho provato con / senza lo spazio dei nomi all'inizio, scambiando, ecc. niente.
Spero che un altro paio di occhi riesca a distinguerlo.
Grazie.
Modifica system.serviceModel
<system.serviceModel>
<bindings>
<!-- wsHttpBinding -->
<wsHttpBinding>
<binding name="wsHttpEndpointBinding">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
<!-- webHttpBinding -->
<webHttpBinding>
<binding name="wsHttps" >
<security mode="Transport"/>
</binding>
</webHttpBinding>
<!-- Basic binding -->
<basicHttpBinding>
<binding name="TransportSecurity">
<security mode="Transport">
<message clientCredentialType="UserName"/>
<!-- transport clientCredentialType="None"/-->
</security>
</binding>
</basicHttpBinding>
<!-- customBinding>
<binding name="WebHttpBinding_IService">
textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
messageVersion="Soap12" writeEncoding="utf-8">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</textMessageEncoding>
<httpsTransport manualAddressing="false"/>
</binding>
</customBinding -->
<!-- Another custom binding -->
<customBinding>
<binding name="CustomMapper">
<webMessageEncoding webContentTypeMapperType=
"IndexingService.CustomContentTypeMapper, IndexingService" />
<httpTransport manualAddressing="true" />
</binding>
</customBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="false" />
<services>
<service behaviorConfiguration="ServiceBehavior" name="Service">
<!-- Service Endpoints -->
<!-- since we're hosting in IIS, baseAddress is not required
<host>
<baseAddresses>
<add baseAddress="https://mysslserver.com/Service.svc"/>
</baseAddresses>
</host>
-->
<endpoint address="https://mysslserver.com/Service.svc"
binding="wsHttpBinding"
bindingConfiguration="wsHttpEndpointBinding"
contract="IService"
name="wsHttpEndpoint">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically.
-->
<!--identity>
<dns value="https://mysslserver.com"/>
</identity-->
</endpoint>
<!-- endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/ -->
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<!-- Setup Security/Error Auditing -->
<serviceSecurityAudit auditLogLocation="Application"
suppressAuditFailure="false"
serviceAuthorizationAuditLevel="Failure"
messageAuthenticationAuditLevel="Failure" />
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true"
httpsGetUrl="https://mysslserver.com/Service.svc"/>
<serviceDebug includeExceptionDetailInFaults="false" />
<serviceCredentials>
<!-- Use our own custom validation -->
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="CustomValidator.CustomUserNameValidator, CustomValidator"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
<!-- serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpsGetEnabled="true"
httpsGetUrl="https://mysslserver.com/Service.svc" />
To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior-->
</behaviors>
</system.serviceModel>
Soluzione
Ho deciso di dargli un'altra pugnalata e non mi è piaciuto avere il mio validatore personalizzato in un'altra libreria.
Quindi ho creato una nuova classe in App_Code e ci sono andata ...
Quello che segue è ciò che l'ha risolto,
="CustomValidator.CustomUserNameValidator, App_Code"
Altri suggerimenti
Quando fai riferimento al validatore personalizzato con i valori
="CustomValidator.CustomUserNameValidator, CustomValidator"
Il primo valore è il nome del tipo e il secondo è il nome dell'assembly in cui trovare il tipo. Quindi lo suggerirei in primo luogo il tuo servizio è attualmente in qualche altro assemblaggio come MyService In quel caso avevi davvero bisogno del tuo file di configurazione per dire
="CustomValidator.CustomUserNameValidator, MyService"
Sospetto che quando avrai creato la tua nuova libreria di classi per il tuo validatore, hai chiamato il tuo progetto CustomValidator (che lo farà output un assembly chiamato CustomValidator.dll), e quindi ora tuo config funzionerà (cioè non ha nulla a che fare con l'essere in un separato libreria di classi - capita solo che la denominazione dell'assembly il riferimento in web.config è ora valido)
Sembra un po 'strano, ma la soluzione era creare una libreria di classi separata e fare riferimento alla sua DLL nel mio servizio WCF.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.ServiceModel;
/// <summary>
/// Summary description for CustomUsernamePasswordValidator
/// </summary>
namespace CustomValidator
{
public class CustomUserNameValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (null == userName || null == password)
{
throw new ArgumentNullException();
}
if (!AuthenticateUser(userName, password))
throw new SecurityTokenValidationException("Invalid Credentials");
else
{
// do nothing - they're good
}
}
public bool AuthenticateUser(string userName, string password)
{
if (userName != "userbill" || password != "passwordbill")
{
return false;
}
else
{
return true;
}
}
}
}
Ho quindi aggiunto un riferimento a System.IdentityModel e System.ServiceModel.
La sezione serviceCredentials per il servizio WCF è ora cambiata in questo:
<serviceCredentials>
<!-- Use our own custom validation -->
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="CustomValidator.CustomUserNameValidator, CustomValidator"/>
</serviceCredentials>
Spero che aiuti qualcuno.
L'ho provato con credenziali non valide e mi aspettavo di vedere le mie " Credenziali non valide " Messaggio. Invece sto ricevendo " Almeno un token di sicurezza nel messaggio non può essere convalidato. & Quot;
A parte questo, questa cosa è finalmente operativa!
Semplicemente leggendo questo dato che è stato utile per un POC ho dovuto iniziare rapidamente. In risposta a ELHaix sopra ... questo dovrebbe funzionare per garantire che il tuo errore descrittivo personalizzato venga restituito al client:
using System.ServiceModel
...
throw new FaultException("Invalid Credentials - Custom Error");