В C#
массивы лучше всего использовать, когда число элементов известно и фиксировано. В противном случае для добавления / удаления элементов будет достаточно общего List<T>
.
Я думаю, что вы спрашиваете, как разработать модель данных для зарегистрированных пользователей и как взаимодействовать с этой моделью с помощью пользовательского интерфейса.
Эта головоломка состоит из нескольких частей:
1. Модель данных
Начните с класса для хранения информации о пользователе (LoginUser
ниже) и класса для хранения списка авторизованных пользователей (UserRegistry
ниже).

Добавьте методы для загрузки / сохранения реестра пользователей в Xml или любом другом хранилище, которое вы пожелаете. В моем примере ниже я использую встроенный XmlSerializer для go от данных к файлу и обратно.
Полный код в моем примере
/// <summary>
/// The user registry.
/// </summary>
[Serializable()]
[XmlType(AnonymousType = true)]
[XmlRoot(ElementName = "Users", Namespace = "", IsNullable = false)]
public partial class UserRegistry
{
public UserRegistry()
{
this.Users= new List<LoginUser>();
}
/// <summary>
/// The list of users
/// </summary>
[XmlElement("User")]
public List<LoginUser> Users { get; set; }
/// <summary>
/// Find the user in the list that matches the userId
/// </summary>
public LoginUser this[string userId]
{
get
{
return Users.FirstOrDefault((item) => item.UserId.ToLowerInvariant().Equals(userId.ToLowerInvariant()));
}
}
public void Add(LoginUser user)
{
this.Users.Add(user);
}
/// <summary>
/// Load a user list from an xml string.
/// </summary>
public static UserRegistry FromXml(string xml)
{
var fs = new StringReader(xml);
var xs = new XmlSerializer(typeof(UserRegistry));
var list = xs.Deserialize(fs) as UserRegistry;
fs.Close();
return list;
}
/// <summary>
/// Save a user list to an xml string.
/// </summary>
public string SaveToXml()
{
var fs = new StringWriter();
var xs = new XmlSerializer(typeof(UserRegistry));
xs.Serialize(fs, this);
fs.Close();
return fs.ToString();
}
}
/// <summary>
/// A user entry
/// </summary>
[Serializable()]
[XmlType(AnonymousType = true)]
public partial class LoginUser
{
public static readonly LoginUser Empty = new LoginUser()
{
UserId=string.Empty,
Salt = string.Empty,
PasswordHash = string.Empty
};
/// <summary>
/// The list of users
/// </summary>
[XmlAttribute("id")]
public string UserId
{
get;
set;
}
/// <summary>
/// The salted hash of the password
/// </summary>
[XmlAttribute("pwd")]
public string PasswordHash
{
get;
set;
}
/// <summary>
/// The salt value used in the hash.
/// </summary>
[XmlAttribute("salt")]
public string Salt
{
get;
set;
}
}
и образец, соответствующий XML file
// File: "UserList.xml"
<?xml version="1.0" encoding="utf-8" ?>
<Users>
<User id="sue@email.com" pwd="Ei9p5Kiy8h7cy0nAxNimukxRhH4=" salt="OrAx1kBufa8=" />
<User id="john@email.com" pwd="teeHjCrXzCxWosgZVTMWWeIvaso=" salt="hxQPkMK8t+0=" />
</Users>
Обратите внимание, что оба зарегистрированных пользователя выше используют один и тот же пароль, и, используя случайную "соль", пароль ha sh отличается. Вышеприведенная реализация не является наиболее безопасной, но это базовый шаг выше, чем хранение паролей в виде текста. Пароль, который я использовал для генерации обоих хешей выше, это строка "12345678"
.
2. Форма входа
Форма входа basi c содержит текстовые поля для имени пользователя и пароля

, она также проверяет длину пароля перед включением кнопки OK . Эта кнопка содержит код, который создает LoginUser
из пользовательского интерфейса.
Форма имеет два свойства: LoginUser
для текущего пользователя и UserRegistry
для списка зарегистрированных пользователей. Список заполняется при загрузке формы из файла XML. Текущий пользователь изначально пуст. Для удобства я включаю автозаполнение в текстовом поле имени пользователя, используя список зарегистрированных пользователей.
public partial class LoginForm1 : Form
{
public LoginUser User { get; set; }
public UserRegistry UserRegistry { get; private set; }
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.UserRegistry = UserRegistry.FromXml(File.ReadAllText("UserList.xml"));
var usernames = UserRegistry.Users.Select((item) => item.UserId).ToArray();
userNameTextBox.AutoCompleteSource = AutoCompleteSource.CustomSource;
userNameTextBox.AutoCompleteCustomSource.AddRange(usernames);
this.User = LoginUser.Empty;
}
// other code omitted
}
Основная часть кода - проверка пароля и регистрация нового пользователя. У меня есть два метода, IsUserValid()
и RegisterUser()
, которые вызываются из обработчика кнопки OK .
public static bool IsUserValid(LoginUser user, string password)
{
var salt = Convert.FromBase64String(user.Salt);
var pwd = Encoding.UTF7.GetBytes(password);
var buffer = new byte[pwd.Length + salt.Length];
Array.Copy(pwd, 0, buffer, 0, pwd.Length);
Array.Copy(salt, 0, buffer, pwd.Length, salt.Length);
var hash = sha1.ComputeHash(buffer);
if (user.PasswordHash.Equals(Convert.ToBase64String(hash)))
{
return true;
}
return false;
}
public static LoginUser RegisterUser(string userName, string password)
{
var salt = new byte[8];
rng.GetBytes(salt);
var pwd = Encoding.UTF7.GetBytes(password);
var buffer = new byte[pwd.Length + salt.Length];
Array.Copy(pwd, 0, buffer, 0, pwd.Length);
Array.Copy(salt, 0, buffer, pwd.Length, salt.Length);
var hash = sha1.ComputeHash(buffer);
return new LoginUser()
{
UserId = userName,
Salt = Convert.ToBase64String(salt),
PasswordHash = Convert.ToBase64String(hash)
};
}
private void okButton_Click(object sender, EventArgs e)
{
this.User = UserRegistry[userNameTextBox.Text];
if (this.User!=null)
{
if (IsUserValid(User, passwordTextBox.Text))
{
this.DialogResult = DialogResult.OK;
this.Close();
}
else
{
passwordTextBox.Clear();
MessageBox.Show($"Incorrect password. Try Again.", "Login");
}
}
else
{
if (MessageBox.Show($"User {userNameTextBox.Text} Not Found. Do you want to register?",
"Login", MessageBoxButtons.YesNo)==DialogResult.Yes)
{
this.User = RegisterUser(userNameTextBox.Text, passwordTextBox.Text);
this.UserRegistry.Add(User);
MessageBox.Show($"User {userNameTextBox.Text} Registered.", "Login");
this.DialogResult = DialogResult.OK;
File.WriteAllText("UserList.xml", UserRegistry.SaveToXml());
this.Close();
}
}
}
3. Проверка правильности
Основная форма должна вызывать форму входа в систему, и если пользователь действителен, она вернет действительную запись в свойство User
и вернет DialogResult.OK
из метода .ShowDialog()
формы.
public partial class MDIParent1 : Form
{
public MDIParent1()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
LoginForm1 login = new LoginForm1();
login.StartPosition = FormStartPosition.CenterScreen;
if (login.ShowDialog()==DialogResult.OK)
{
// Valid user
userNameToolStripLabel.Text = login.User.UserId;
return;
}
this.Close();
}
}
В моем примере я использую личность пользователя в правом нижнем углу основной формы.
