Click here to Skip to main content
15,887,175 members
Please Sign up or sign in to vote.
5.00/5 (2 votes)
See more:
Hi everyone!
I have a base class AuthenticatorBase that has ability to log in users with different authentication subjects - login & password and token.
Class looks like this:
C#
 public abstract class AuthenticatorBase {

        public abstract LogInResult LogIn(object authSubject);

        public abstract void LogOut(string sessionKey);
}


The sub-class that authenticates with login & password

C#
public class BasicAuthenticator : AuthenticatorBase {

       public override LogInResult Authenticate(object authSubject) {
            LogInData credentials = authSubject as LogInData;
              
            if (DbContext.Security.Authorize(credentials))
              ...............
       }
    }


The sub-class that authenticates with token
C#
public class TokenBasedAuthenticator: AuthenticatorBase {

    public override LogInResult Authenticate(object authSubject)
    {
        string token = authSubject as string;

        User user;
        if (DbContext.Security.LogInWithToken(token, out user))
            ...........
    }
}

What I don't like in this code is the parameter authSubject of type System.Object, I need to cast it in sub-classes. If I use, say BasicAuthenticator, I might pass invalid type as parameter.
I know I can make generic type AuthenticatorBase<TAuthSubject> and have two sub-classes BasicAuthenticator: AuthenticatorBase<LogInData> and TokenBasedAuthenticator : AuthenticatorBase<string>. But what if I need to have them in list, both generic classes don't have a common interface.
I could create an additional interface like this:

C#
public interface IAuthenticator {

      LogInResult LogIn(object authSubject);
}

public abstract class AuthenticatorBase<tauthsubject>: IAuthenticator {

   public abstract LogInResult LogIn(TAuthSubject authSubject);

   // implementing interface
   LogInResult IAuthenticator.LogIn(object authSubject)
   {
       return LogIn((TAuthSubject)authSubject);
   }
}

Now I can store instances of IAuthenticator in the list, but this seems to be very overwhelmed. What's the best way to get rid of the parameter authSubject as type System.Object??? I want to call it and pass correct instance of type to authenticators without having to think about correct types that authenticator accepts. Thanks

What I have tried:

Tried to use my code, but I find it overloaded
Posted
Updated 10-Nov-16 1:09am

1 solution

Using generics is the right way to go, however if adding them to a collection is the issue then you can make them implement an additional interface like this

C#
public interface IAuthenticatorBase
{
    // you don't need to define this here, you could leave this interface
    // as an empty token interface
    void LogOut(string sessionKey);
}

public abstract class AuthenticatorBase<TAuthSubject> : IAuthenticatorBase
{
    public abstract LogInResult LogIn(TAuthSubject authSubject);

    public abstract void LogOut(string sessionKey);
}

public class BasicAuthenticator : AuthenticatorBase<LogInData>
{
    public override LogInResult LogIn(LogInData authSubject)
    {
        throw new NotImplementedException();
    }

    public override void LogOut(string sessionKey)
    {
        throw new NotImplementedException();
    }
}

public class TokenBasedAuthenticator : AuthenticatorBase<string>
{
    public override LogInResult LogIn(string authSubject)
    {
        throw new NotImplementedException();
    }

    public override void LogOut(string sessionKey)
    {
        throw new NotImplementedException();
    }
}


You would then have a list of IAuthenticatorBase

C#
List<IAuthenticatorBase> myAuths = new List<IAuthenticatorBase>();
myAuths.Add(new BasicAuthenticator());
myAuths.Add(new TokenBasedAuthenticator());

foreach (IAuthenticatorBase auth in myAuths)
{
    // this is where it gets a bit naff but if you want to
    // deal with disparate types in a collection then at some point you
    // have to convert them to their concrete versions
    if (auth is BasicAuthenticator)
    {
        BasicAuthenticator basicAuthenticator = auth as BasicAuthenticator;
    }
    else if (auth is TokenBasedAuthenticator)
    {
        TokenBasedAuthenticator tokenBasedAuthenticator = auth as TokenBasedAuthenticator;
    }
}
 
Share this answer
 
Comments
NickResh777 10-Nov-16 7:36am    
Thanks. But is it correct to convert from interface to class? Or in this case it has no issues? I see now
F-ES Sitecore 10-Nov-16 9:21am    
The IAuthenticatorBase is really just a "tag" to mark things you can add to your collection, it will probably have no actual methods so you'll have to convert the object that implements it to the concrete class (or to AuthenticatorBase<tauthsubject> if suitable) in order to access the actual methods.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900