Как сделать недействительным сеанс 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;
}
}
2 ответа
Вызов исключения - безусловно, самый простой вариант, потому что WCF обеспечивает невозможность повторного использования сеанса. Из того, что я понял, что вы хотели бы, чтобы сторонний компонент выполнял, довольно близко подходит к этой функциональности. Но вместо того, чтобы заставлять клиента снова вызывать IsInitialized, вы заставляете клиента создавать новое соединение. Это выглядит как маленькая разница для меня.
Альтернативой было бы иметь закрытую переменную bool _authorised и проверять эту переменную при каждом вызове метода.
Сделайте что-то вроде этого:
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();
}
Это приведет к неисправности канала, и клиенту придется заново установить сеанс.