NickResh777 Ответов: 1

Удостоверение. Дизайн класса


Всем привет!
У меня есть базовый класс AuthenticatorBase он имеет возможность входить в систему пользователей с различными субъектами аутентификации-логином и паролем и токеном.
Класс выглядит так:
 public abstract class AuthenticatorBase {

        public abstract LogInResult LogIn(object authSubject);

        public abstract void LogOut(string sessionKey);
}


Подкласс, который аутентифицируется с помощью логина и пароля

public class BasicAuthenticator : AuthenticatorBase {

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


Подкласс, который аутентифицируется с помощью токена
public class TokenBasedAuthenticator: AuthenticatorBase {

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

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

Что мне не нравится в этом коде, так это параметр authSubject типа Система.Объект, Мне нужно разыграть его в подклассах. Если я использую, скажем BasicAuthenticator, Я мог бы передать недопустимый тип в качестве параметра.
Я знаю, что могу сделать универсальный тип AuthenticatorBase & lt;TAuthSubject> и имеют два подкласса BasicAuthenticator: AuthenticatorBase & lt;LogInData> и TokenBasedAuthenticator : AuthenticatorBase & lt;string> Но что делать, если мне нужно иметь их в списке, оба универсальных класса не имеют общего интерфейса.
Я мог бы создать дополнительный интерфейс, подобный этому:

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);
   }
}

Теперь я могу хранить экземпляры IAuthenticator в списке, но это, кажется, очень перегружено. Как лучше всего избавиться от этого параметра authSubject как тип Система.Объект?? Я хочу вызвать его и передать правильный экземпляр типа аутентификаторам, не думая о правильных типах, которые принимает Аутентификатор. Спасибо

Что я уже пробовал:

Пытался использовать мой код, но он оказался перегруженным

1 Ответов

Рейтинг:
12

F-ES Sitecore

Использование дженериков-это правильный путь, однако если проблема заключается в добавлении их в коллекцию, то вы можете заставить их реализовать дополнительный интерфейс, подобный этому

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();
    }
}


Тогда у вас будет список IAuthenticatorBase

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;
    }
}


NickResh777

Спасибо. Но правильно ли переходить из интерфейса в класс? Или в данном случае у него нет никаких проблем? Теперь я понимаю

F-ES Sitecore

В IAuthenticatorBase на самом деле просто "тегов", чтобы отметить вещи, которые вы можете добавить в свою коллекцию, он, вероятно, не имеют реальных методов, так что вы будете иметь, чтобы преобразовать объект, который реализует его к конкретному классу (или AuthenticatorBase&ЛТ;tauthsubject&ГТ; если любой), чтобы получить доступ к фактическим методикам.