Basic authentication and WCF

2019-05-24 23:21发布

问题:

I'm trying to learn WCF, but I don't really understand what I have to do. I have a database with usernames and passwords and the user should authenticate before he may use the service.

For now, the username and password is hardcoded:

class UsernameAuthentication : UserNamePasswordValidator
{
    /// <summary>
    /// When overridden in a derived class, validates the specified username and password.
    /// </summary>
    /// <param name="userName">The username to validate.</param><param name="password">The password to validate.</param>
    public override void Validate(string userName, string password)
    {
        var ok = (userName == "test") && (password == "test");
        if (ok == false)
            throw new AuthenticationException("username and password does not match");
    }
}

My service is very simple:

public class Service1 : IService1
{
    public int Add(int a, int b)
    {
        return a + b;
    }

    public int Subtract(int a, int b)
    {
        return a - b;
    }
}

My question is: what exactly do I have to change in the web.config file to make this work? I've looked at some tutorials, but don't really understand the needed changes..

Also, what I'm trying to do - authenticate a user before he may access the service, is this the correct way of doing it?

Thanks

EDIT: My config file:

<?xml version="1.0"?>
<configuration>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5"/>
  </system.web>
  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="Binding1">
          <security mode="Message">
            <message clientCredentialType="UserName" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceCredentials>
            <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WcfService1.UsernameAuthentication, service1" />
          </serviceCredentials>
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <!-- 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="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <protocolMapping>
        <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>    
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
    <directoryBrowse enabled="true"/>
  </system.webServer>
</configuration>

Error: service1.svc cannot be activated.

回答1:

You have to specify in the web.config that you will use username/password credentials and that you use a custom password validator.

The binding of your service should have set a type of security (Transport or Message, what suits you best) and for that type of security you must set the credentials you want to use (username and password).

<system.serviceModel> 
  <bindings>
  <wsHttpBinding>
      <binding name="Binding1" ...>
        <security mode="Message">
          <message clientCredentialType="UserName" />
        </security>
      </binding>        
    </wsHttpBinding>
  </bindings>
</system.serviceModel>

Where ... means many other settings specific to your service.

Take into account that only certain types of bindings and security modes support this type of credentials, but MSDN has all the information you may need.

If you do not set the credentials to username and password, you won't authenticate users this way.

To tell the service to use your password validator you need to add something like this:

<behaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehavior">
            <serviceCredentials>
              <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Microsoft.ServiceModel.Samples.CalculatorService.CustomUserNameValidator, service" />
            </serviceCredentials>
         .....
         </serviceBehaviors>
</behaviors> 

Where Microsoft.ServiceModel.Samples.CalculatorService is the namespace under which you have the custom validator, CustomUserNameValidator is teh custom validator (UserNamePasswordValidator in your case), and service is the name of the service.

Otherwise, the service would expect a default validator, like the ASP.NET Membership Provider.

The service credentials must be put in your service behaviour.

Also, don't forget to link the behaviour to the service definition.

<services>
  <service behaviorConfiguration="ServiceBehavior" name="ServiceName">
    <endpoint address="" binding="basicHttpBinding" bindingConfiguration="Binding1" contract="ContractName" />
     ....
  </service>
</services>

NOTE: There are many more settings in the web.config that I didn't show. Names of elements are only orientative. This is just for making username credentials work.

You may check MSDN because they have many great tutorials on this, like this one http://msdn.microsoft.com/en-us/library/aa702565.aspx, http://msdn.microsoft.com/en-us/library/aa354513.aspx.

And yes, in fact if you configure this in the right way, it will authenticate clients (users, client services) before given them permission to run the service methods.



标签: c# wcf security