Как сделать недействительным сеанс C # WCF, если логин неверен

Я пишу удаленную службу для приложения, использующего WCF, в котором информация для входа в систему хранится в базе данных. Служба требует установления сеанса через вызов входа в систему или создания учетной записи. Нет никакого вовлеченного ASP.

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

Глядя на некоторые другие вопросы, я обнаружил плюсы и минусы двух способов сделать сеанс недействительным. Это делается трудным путем, вызывая исключение FaultException; другой - с более мягкими манерами, с сохранением принятых идентификаторов сеансов.

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

Итак, вопрос: существует ли третий путь, который позволяет службе аннулировать инициализацию сеанса и передать ее клиенту, чтобы он был вынужден сделать новый вызов IsInitiating?

Уменьшенная версия кода, который у меня есть:

[DataContractAttribute]
public class AccountLoginFault
{
    public AccountLoginFault (string message)
    {
        this.Message = message;
    }

    [DataMemberAttribute]
    public string Message { get; set; }
}

[ServiceContract (SessionMode = SessionMode.Required)]
public interface IAccountService
{
    [OperationContract (
        IsInitiating = true)]
    [FaultContractAttribute (
        typeof (AccountLoginFault),
        ProtectionLevel = ProtectionLevel.EncryptAndSign)]
    bool Login (AccountData account, out string message);
}

[ServiceBehavior (
    ConcurrencyMode = ConcurrencyMode.Single,
    InstanceContextMode = InstanceContextMode.PerSession)]
public class AccountService : IAccountService
{
    public bool Login (AccountData account, out string message)
    {
        UserManager userdb = ChessServerDB.UserManager;
        bool result = false;
        message = String.Empty;

        UserData userData = userdb.GetUserData (account.Name);

        if (userData.Name.Equals (account.Name)
            && userData.Password.Equals (account.Password))
        {
            // Option one
            // Get lock
            // this.AcceptedSessions.Add (session.ID);
            // Release lock

            result = true;
        } else
        {
            result = false;

            // Option two
            // Do something with session context to mark it as not properly initialized.
            // message = "Incorrect account name or password. Account provided was " + account.Name;

            // Option three
            throw new FaultException<AccountLoginFault> (
                new AccountLoginFault (
                    "Incorrect account name or password. Account provided was " + account.Name));
        }

        return result;
    }
}

person Elideb    schedule 20.10.2010    source источник
comment
Какую безопасность вы установили для этой услуги? Сообщение или транспорт?   -  person Steve Ellinger    schedule 20.10.2010
comment
Все еще не определились. Предлагает ли какой-либо из них механизм для выполнения того, о чем я спрашиваю, чего не хватает другому?   -  person Elideb    schedule 20.10.2010
comment
Безопасность не имеет значения. Сеансы поддержки транспорта и сообщений. Однако для HTTPS вы должны использовать привязку WSHTTP.   -  person John K    schedule 11.06.2011


Ответы (2)


Создание исключения - это, безусловно, самый простой вариант, поскольку WCF требует, чтобы сеанс нельзя было повторно использовать. Насколько я понимаю, то, что вы хотели бы, чтобы сторонний компонент выполнял, очень близко к этой функциональности. Но вместо того, чтобы заставлять клиента снова вызывать IsInitialized, вы должны заставить клиента создать новое соединение. Мне это кажется очень маленькой разницей.

Альтернативой было бы иметь частную переменную bool _authorised и проверять эту переменную при каждом вызове метода.

person Pieter van Ginkel    schedule 20.10.2010
comment
FaultException - это способ, которым я его реализую, но мне все время интересно, есть ли более элегантный способ сделать это с использованием механизмов WCF. Кроме того, исключения сильно влияют на производительность, если пользовательская база значительно масштабируется, а я стараюсь свести их к минимуму. - person Elideb; 20.10.2010
comment
Несмотря на то, что многие пользователи войдут в систему, я не могу поверить, что запрос на вход будет составлять большой процент от общего числа ваших запросов; конечно, не неудачные запросы входа в систему. Я не ожидал, что это станет проблемой. Если из-за этого вас действительно беспокоят проблемы с производительностью, выберите вторую стратегию с частной переменной. - person Pieter van Ginkel; 20.10.2010
comment
Похоже, лучшего решения, чем использование FaultException, нет. Спасибо. - person Elideb; 21.10.2010
comment
Есть способ получше, см. Мой ответ. - person John K; 21.06.2011

Сделайте что-нибудь вроде этого:

public ConnectResponseDTO Connect(ConnectRequestDTO request) {
    ...
    if(LoginFailed)
        OperationContext.Current.OperationCompleted += FaultSession;       
}

private void FaultSession(object sender, EventArgs e) {
    var context = (OperationContext) sender;
    context.Channel.Abort();
}

Это приведет к сбою канала, и клиенту придется повторно установить сеанс.

person John K    schedule 27.05.2011