基於 Visual Studio、C#、ASP.NET WebForms (.aspx) 和 SQL Server 構建登錄驗證功能。本文從頁面佈局、數據庫表設計、ADO.NET 參數化查詢防注入、會話管理到安全最佳實踐,提供端到端完整代碼示例。
CREATE TABLE Users (
UserID INT PRIMARY KEY IDENTITY(1,1),
Username NVARCHAR(50) NOT NULL UNIQUE,
PasswordHash NVARCHAR(256) NOT NULL, -- 存儲 BCrypt/Argon2 哈希,絕不存明文
Salt NVARCHAR(32), -- 若用 PBKDF2 需要鹽
Email NVARCHAR(100),
CreatedAt DATETIME DEFAULT GETDATE(),
LastLogin DATETIME,
IsActive BIT DEFAULT 1
);
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Login.aspx.cs" Inherits="WebApp.Login" %>
<!DOCTYPE html>
<html>
<head><title>用戶登錄</title></head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="lblMsg" runat="server" ForeColor="Red" /><br />
用戶名: <asp:TextBox ID="txtUser" runat="server" /><br />
密碼: <asp:TextBox ID="txtPwd" runat="server" TextMode="Password" /><br />
<asp:Button ID="btnLogin" runat="server" Text="登錄" OnClick="btnLogin_Click" />
</div>
</form>
</body>
</html>
using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using BCrypt.Net; // NuGet: BCrypt.Net-Next
namespace WebApp {
public partial class Login : System.Web.UI.Page {
protected void btnLogin_Click(object sender, EventArgs e) {
string username = txtUser.Text.Trim();
string password = txtPwd.Text;
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password)) {
lblMsg.Text = "用戶名和密碼不能為空";
return;
}
string connStr = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
// 參數化查詢防 SQL 注入
string sql = "SELECT PasswordHash FROM Users WHERE Username = @User AND IsActive = 1";
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(sql, conn)) {
cmd.Parameters.Add("@User", SqlDbType.NVarChar, 50).Value = username;
conn.Open();
object result = cmd.ExecuteScalar();
if (result != null && result != DBNull.Value) {
string storedHash = result.ToString();
// 驗證密碼哈希
if (BCrypt.Verify(password, storedHash)) {
// 登錄成功:建立會話
Session["UserID"] = username;
Session["LoginTime"] = DateTime.Now;
// 更新最後登錄時間(可異步)
UpdateLastLogin(username, connStr);
Response.Redirect("Default.aspx"); // 跳轉主頁
} else {
lblMsg.Text = "密碼錯誤";
}
} else {
lblMsg.Text = "用戶不存在或已禁用";
}
}
}
private void UpdateLastLogin(string username, string connStr) {
string sql = "UPDATE Users SET LastLogin = GETDATE() WHERE Username = @User";
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(sql, conn)) {
cmd.Parameters.Add("@User", SqlDbType.NVarChar, 50).Value = username;
conn.Open();
cmd.ExecuteNonQuery();
}
}
}
}
<connectionStrings>
<add name="DefaultConnection"
connectionString="Server=.;Database=MyAppDB;Integrated Security=true;"
providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<authentication mode="Forms">
<forms loginUrl="Login.aspx" timeout="30" />
</authentication>
<authorization>
<deny users="?" /> <!-- 拒絕匿名訪問 -->
</authorization>
</system.web>
HttpOnly、Secure Cookie 旗標,會話固定攻擊防護。