Monday, January 04, 2010

WCF – Authentication Service & Solution Structure




I realize that WCF has been out for quite some time now, but my team and I are getting ready to start using it now. So I started playing around with how I think we should setup the project. I thought I’d share it to see if I could get some feedback. I tweeted a question about it, but got no response, so I assume my idea is a good one and not going to lead me down a road of catastrophe…at least I hope!

Well let’s get started and you can let me know what you think. First off let me show you my structure, which is VERY similar to my MVC structure.

CropperCapture[10]

So I have my test projects in my Tests solution folder, my Core (has ALL code), and my WCF project at the bottom. I’m glad Jimmy Bogard had blogged about this setup because I’m REALLY liking it. Let’s start with the Core.Interfaces.

It does one thing and that is, checks the user’s password. Here’s the code:

    [ServiceContract]
public interface IAuthenticationService
{
[
OperationContract]
bool PasswordMatches(User user, string password);
}

Obviously the attributes make it into a WCF contract. The User class looks like this:

    [DataContract]
public class User
{
[
DataMember]
public string Username { get; set; }
[
DataMember]
public string DisplayName { get; set; }
[
DataMember]
public string EmailAddress { get; set; }
[
DataMember]
public string PasswordHash { get; set; }
[
DataMember]
public string PasswordSalt { get; set; }
}

Here you need to add the attributes to make them accessible for the service to use the class. You only need the [DataMember] on the properties that you want accessible. I’ve chosen to set it on all of them. Let’s get to the implementation of the IAuthenticationService.

    public class AuthenticationService : IAuthenticationService
{
public bool PasswordMatches(User user, string password)
{
if (password == "test")
return true;

return false;
}
}

Very simple example, eventually this will have my Active Directory authentication code in it. I also created an AuthenticationService decorated with Logging so I could log failed attempts. Here’s what it looks like:

    public class AuthenticationServiceWithLogging : IAuthenticationService
{
private readonly IAuthenticationService _authenticationService;
public AuthenticationServiceWithLogging() : this(DependencyRegistrar.Resolve<IAuthenticationService>())
{ }

public AuthenticationServiceWithLogging(IAuthenticationService authenticationService)
{
_authenticationService = authenticationService;
}

protected static readonly ILog log = LogManager.GetLogger(typeof(AuthenticationServiceWithLogging));
public bool PasswordMatches(User user, string password)
{
var isAuthenticated = _authenticationService.PasswordMatches(user, password);
if (isAuthenticated)
return true;

log.Warn(user.DisplayName +
" - Invalid Credentials.");
return false;
}
}

Notice I have the StructureMap code in the empty constructor. The reason I have to have an empty constructor is because of the way WCF works…at least it got rid of one of the errors I was receiving :) I may be missing something, if so, please let me know. I read Jimmy Bogard’s post on WCF with StructureMap and thought his solution was more than what I needed for the time being. Trying to stick with the YAGNI principle. So this implementation uses Log4net, which I have not wrapped in my own code yet, but I will! Since this isn’t a log4net or StructureMap post, I won’t go into any other details.


Okay, let’s look at the WCF project code, which is VERY simple indeed! Here’s the AuthenticationServiceWithLogging.svc code:

<%@ ServiceHost Language="C#" Service="Core.Services.AuthenticationServiceWithLogging" %>

Done!


Now for the Global.asax:

<%@ Application Inherits="Core.Global" Language="C#" %>

Done!


All done other than the web.config settings:

  <system.serviceModel>
<
bindings>
<
basicHttpBinding>
<
binding name="SecureBasicHttpBinding">
<
security mode="Transport">
<
transport clientCredentialType="None" />
</
security>
</
binding>
</
basicHttpBinding>
</
bindings>
<
behaviors>
<
serviceBehaviors>
<
behavior name="Core.Services.AuthenticationServiceWithLoggingBehavior">
<!--
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />-->
<
serviceMetadata httpGetEnabled="true" />
<
serviceDebug includeExceptionDetailInFaults="false" />
</
behavior>
</
serviceBehaviors>
</
behaviors>
<
services>
<
service behaviorConfiguration="Core.Services.AuthenticationServiceWithLoggingBehavior"
name="
Core.Services.AuthenticationServiceWithLogging">
<!--
<endpoint bindingConfiguration="SecureBasicHttpBinding" address="" binding="basicHttpBinding" contract="Core.Interfaces.IAuthenticationService"/>-->
<
endpoint address="" binding="basicHttpBinding" contract="Core.Interfaces.IAuthenticationService"/>
<
endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</
service>
</
services>
</
system.serviceModel>

You should notice the commented out code in gray. If you want to use your service via HTTPS, you’ll need to uncomment that code and delete the lines below it.


So that’s it! Pretty simple and clean I think. Please let me know what your thoughts are and whether I’m WAY off on WCF :)


As always, thanks for reading!

kick it on DotNetKicks.com

blog comments powered by Disqus
Related Posts Plugin for WordPress, Blogger...