status 字段,直接用變量 status (未定義) 比較。private void btnLogin_Click(object sender, EventArgs e) {
// 1. 前端驗證
if (string.IsNullOrWhiteSpace(txtUserName.Text) ||
string.IsNullOrWhiteSpace(txtPassword.Text)) {
MessageBox.Show("用戶名和密碼不能為空");
return;
}
string role = cmbRole.SelectedItem?.ToString();
if (string.IsNullOrEmpty(role)) {
MessageBox.Show("請選擇角色");
return;
}
// 2. 參數化查詢
const string sql = @"
SELECT user_name, status
FROM user_info
WHERE user_name = @user AND user_pwd = @pwd";
using (var conn = new SqlConnection(connStr))
using (var cmd = new SqlCommand(sql, conn)) {
cmd.Parameters.AddWithValue("@user", txtUserName.Text.Trim());
cmd.Parameters.AddWithValue("@pwd", txtPassword.Text.Trim()); // 實際應存哈希值!
try {
conn.Open();
using (var reader = cmd.ExecuteReader()) {
if (!reader.Read()) {
MessageBox.Show("用戶名或密碼錯誤");
return;
}
string dbRole = reader["status"].ToString(); // 讀取數據庫角色
if (!string.Equals(dbRole, role, StringComparison.OrdinalIgnoreCase)) {
MessageBox.Show($"該賬號角色為「{dbRole}」,無法以「{role}」身份登錄");
return;
}
// 3. 角色匹配,跳轉對應窗體
Form targetForm = role switch {
"管理員" => new AdminForm(),
"學生" => new StudentForm(),
_ => null
};
if (targetForm != null) {
this.Hide();
targetForm.ShowDialog();
this.Close();
}
}
} catch (Exception ex) {
MessageBox.Show("登錄異常:" + ex.Message);
}
}
}
| 項目 | 原代碼 | 修正版 |
|---|---|---|
| SQL 執行 | 字符串拼接 | 參數化 @user, @pwd |
| 角色比對 | 變量 status 未賦值 |
reader["status"] 讀取數據庫值 |
| 密碼存儲 | 明文 | **必須存 BCrypt/Argon2 哈希**,驗證時 BCrypt.Verify(input, hash) |
| 資源釋放 | 手動 Close() 易漏 |
using 自動 Dispose |
| 窗體跳轉 | 重複 new Form | Switch 表達式統一 |
// 註冊/修改密碼時
string hash = BCrypt.Net.BCrypt.HashPassword(plainPassword, workFactor: 12);
// 存入 user_pwd 字段
// 登錄驗證時
string storedHash = reader["user_pwd"].ToString();
if (!BCrypt.Net.BCrypt.Verify(txtPassword.Text, storedHash)) {
MessageBox.Show("用戶名或密碼錯誤");
return;
}
登錄邏輯核心:**參數化查詢防注入 + 讀取數據庫角色字段比對 + 密碼哈希驗證 + 統一窗體跳轉**。切勿在 SQL 中拼接用戶輸入,切勿明文存儲密碼。