asp.net用户登入验证

该博客详细介绍了如何在ASP.NET中实现用户登录验证,包括配置文件设置、数据库存储过程、自定义登录控件以及用户信息显示。通过示例代码展示了如何检查用户名是否存在、密码匹配、设置和获取用户数据、自定义principal和identity,以及如何在用户登录后展示个性化信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引言

前一段时间有两个朋友问我,为什么在HttpModule中无法获得到Session值,因为他们希望自定义一个HttpModule,然后在其中获取Session来进行用户验证。我奇怪为什么不使用.Net Framework已经提供的验证 机制 ,而要和Asp时一样,自己手工进行cookie+Session验证?我们是基于.Net Framework这个平台进行编程,所以我觉得,在很多情况下,使用Framework已经建立好的机制会显著地提高工作效率,而且.NET Framework内置的验证机制通常也更加 安全

.Net提供了一整套的验证和授权机制,这里验证和授权是不同的概念,验证(Authentication)是指“证明你确实是你所说的人”,通常是提供一个用户名和口令,然后与持久 存储 (比如数据库)中的用户名和口令进行对比。授权(Authorization)是指“你是否有足够的权限做某件事”,此时你的身份已经被证明过了(匿名用户、会员还是管理员),授权通常与用户组或者用户级别联系起来,不同的用户组拥有不同的权限(访问特定页面或者执行特定操作)。

回想一下我刚接触.Net时,也曾经完全绕过.NET的验证,自己编码采用Cookie+Session实现身份验证,并且一个Asp.Net 登录 控件 都没有使用,那时候的理由是: 我要使用自定义的用户表,不能使用Asp.Net安全机制在App_Data下自动生成的AspNetDB.mdf中的一系列数据表 。除此以外,还有一个原因,就是 .Net验证机制的核心IPrincipal和Identity提供的信息用户信息太少了,当在页面后置代码中使用继承来的User属性(IPrincipal类型)时,它的Identity属性只有一个Name与用户数据相关(AuthenticationType与IsAuthenticated都是与验证相关),而很多时候我们都需要许多额外的用户数据。 其实这只是一个误解罢了,以为使用Asp.Net的验证机制和登录控件就一定要使用其附带的数据表,以为Identity就只能携带一个Name属性。

实际上,.NET的安全机制包括了几个部分,除了验证以外,还包括MemberShip、Profile、Role等,我们完全可以只使用它的验证机制,而绕过它的MemberShip、Profile和Role,来实现通常我们用Cookie+Session完成的功能,而且更高效更安全。这篇文章将快速地实现这样的一个流程。

开始前的准备

创建页面,配置Web.config

我们先创建解决方案、建立站点,然后在站点中添加下述文件,它们将会在后面使用:
Asp.Net 用户验证(自定义IPrincipal和IIdentity)_11024
接着对Web.config进行一下配置,首先看根目录下的Web.config:
  1. <?xml version="1.0"?>
  2. <configuration>
  3.     <system.web>
  4.         <authentication mode="Forms">
  5.             <forms timeout="600" slidingExpiration="true" loginUrl="~/SignIn.aspx" />
  6.         </authentication>
  7.     </system.web>
  8.     
  9.     <location path="AuthOnly.aspx" >
  10.         <system.web>
  11.             <authorization>
  12.                 <deny users="?" />
  13.             </authorization>
  14.         </system.web>
  15.     </location>
  16. </configuration>
复制代码
这里我们指定了采用Forms验证,并且设置用户身份验证过期时间为600分钟(默认为30分钟),slidingExpiration的意思是说timeout采用绝对时间还是滑动时间,当采用滑动时间时,如果在timeout时间内再次浏览页面,用户的最后活跃时间将设为当前时间,并重新开始计算,这里我们采用滑动时间。loginUrl指定了登录页面,当匿名用户访问需要验证后才能访问的页面时,将会到自动导航到这里所设置的SignIn.aspx页面,默认为Login.aspx。

接着我们指定AuthOnly.aspx页面为只有验证过的用户才可以访问。然后创建了AuthOnly文件夹,在其下添加了一个web.config,对这个目录进行设置,指定该文件夹下所有文件只允许验证用户进行访问。
  1. <configuration>
  2.     <system.web>
  3.         <authorization>
  4.             <deny users="?" />
  5.         </authorization>
  6.     </system.web>
  7. </configuration>
复制代码
创建用户数据表和数据访问

既然是用户登录,所以我们自然需要一张用户表,在App_Data下创建一个SiteData数据库,然后添加一张User用户表,表的设置如下:
Asp.Net 用户验证(自定义IPrincipal和IIdentity)_11025
这个表模拟了一个小型的论坛用户表,字段的含义基本都是自解释的,UserImage是用户头像的地址,PostCount是用户的发帖数,ReplyCount是用户的回帖数,Level是用户的级别。我已经为表中添加了两条范例数据,其中一条用户名为JimmyZhang,密码为password。
接下来我们需要添加一个存储过程,这个存储过程接收一个name参数,和一个password输出参数,根据name判断User表中是否存在该用户,如果存在,则由password带回正确的密码:
  1. ALTER PROCEDURE dbo.IsValidUser 
  2. (
  3.     @userName varchar(50),
  4.     @password varchar(50) OUTPUT
  5. )
  6. AS
  7.     if Exists(Select Id From [User] Where [Name] = @userName)
  8.         Begin
  9.             Select @password = Password From [User] Where [name]= @userName 
  10.             Select 1        -- Ture
  11.         End    
  12. Select 0        -- false
复制代码
这样做的目的是为了程序能够区分“不存在此用户”和“用户存在,但是密码不正确”这两种情况。如果Select的where子句为[name]=@userName and [password] = @password,则无法进行区分。由数据库带回了正确的密码之后,我们只需要在程序中与用户输入的密码进行对比就可以知道用户的密码是否正确。

接下来我们创建一个强类型DataSet作为我们的数据访问层,因为我发现使用强类型DataSet作数据访问是最快的,基本不需要编写一行代码,在App_Code中添加一个AuthDataSet数据集文件,然后将User表拖进去,另外配置一下UserTableAdapter,添加两个方法,一个是GetUserTable(@name),它根据name参数获得用户信息;一个是IsValidUser(@userName, @password),它调用了上面的存储过程,并且返回一个标量值(0或者1)。
配置好以后,你的AuthDataSet应该和下面一样:
Asp.Net 用户验证(自定义IPrincipal和IIdentity)_11026
如果你查看一下生成的IsValidUser()方法,就会发现它具有这样的签名:
public   virtual   object  IsValidUser( string  userName,  ref   string  password)
由于它返回的是一个object类型,并且接收的是一个ref参数,尽管这样最通用,但是可能不够方便,注意到UserTableAdapter是一个部分类,所以我们可以在App_Code中再创建一个UserTableAdapter部分类,对它进行一个简单的包装:
  1. namespace AuthDataSetTableAdapters {

  2.     // 检查是否是正确的用户名,如果是正确的用户名,带回正确的密码
  3.     public partial class UserTableAdapter {    
  4.         public bool IsValidUserST(string userName, out string password) {
  5.             password = "";
  6.             return Convert.ToBoolean(this.IsValidUser(userName, ref password));        
  7.         }
  8.     }
  9. }
复制代码


这里的方法后缀ST,意思是StrongType(强类型)。好了,现在我们的数据访问就已经OK了,接下来我们看一下第一个页面:SignIn.aspx用户登录页面。

用户登录 -- 为Identity添加用户数据

Login.aspx页面实现

在登录页面,我们需要针对登录用户和非登录用户做不同的处理:如果用户尚未登录,则显示登录用的表单;如果用于已经登录了,则显示登录用户名并进行提示。完成这件事最好就是使用LoginView控件和LoginName控件了:
  1. <asp:LoginView ID="LoginView1" runat="server">
  2.     <LoggedInTemplate>
  3.         <asp:LoginName ID="LoginName1" runat="server" />
  4.         ,你已经登录了^_^ <br /><br />
  5.                 
  6.         你可以选择 <asp:LoginStatus ID="LoginStatus1" runat="server" LogoutPageUrl="~/Logout.aspx" LogoutAction="Redirect"  />
  7.     </LoggedInTemplate>
下面是一个简单的 ASP.NET Core MVC 录注册示例,包括使用 Identity 进行身份验证和管理用户的功能。 1. 首先,打开 Visual Studio 并创建一个新的 ASP.NET Core Web 应用程序。 2. 选择 ASP.NET Core Web 应用程序模板,并选择“Individual User Accounts”身份验证选项。 3. 在解决方案资源管理器中,右键单击项目并选择“管理 NuGet 程序包”。 4. 在 NuGet 程序包管理器中,搜索并安装以下包:Microsoft.AspNetCore.Identity.EntityFrameworkCore、Microsoft.EntityFrameworkCore.SqlServer 和 Microsoft.EntityFrameworkCore.Tools。 5. 打开 Startup.cs 文件,并在 ConfigureServices 方法中添加以下代码: ```csharp services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddIdentity<ApplicationUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders(); services.Configure<IdentityOptions>(options => { // Password settings options.Password.RequireDigit = true; options.Password.RequiredLength = 8; options.Password.RequireNonAlphanumeric = false; options.Password.RequireUppercase = true; options.Password.RequireLowercase = false; // Lockout settings options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30); options.Lockout.MaxFailedAccessAttempts = 10; options.Lockout.AllowedForNewUsers = true; // User settings options.User.RequireUniqueEmail = true; }); ``` 这段代码将添加 Identity 服务,并配置一些身份验证选项。 6. 在 Startup.cs 文件的 Configure 方法中添加以下代码: ```csharp app.UseAuthentication(); ``` 这将启用身份验证中间件。 7. 创建一个名为“AccountController”的新控制器,并添加以下代码: ```csharp public class AccountController : Controller { private readonly SignInManager<ApplicationUser> _signInManager; private readonly UserManager<ApplicationUser> _userManager; public AccountController( UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager) { _userManager = userManager; _signInManager = signInManager; } [HttpGet] public IActionResult Register() { return View(); } [HttpPost] public async Task<IActionResult> Register(RegisterViewModel model) { if (ModelState.IsValid) { var user = new ApplicationUser { UserName = model.Email, Email = model.Email }; var result = await _userManager.CreateAsync(user, model.Password); if (result.Succeeded) { await _signInManager.SignInAsync(user, isPersistent: false); return RedirectToAction("Index", "Home"); } foreach (var error in result.Errors) { ModelState.AddModelError(string.Empty, error.Description); } } return View(model); } [HttpGet] public IActionResult Login() { return View(); } [HttpPost] public async Task<IActionResult> Login(LoginViewModel model) { if (ModelState.IsValid) { var result = await _signInManager.PasswordSignInAsync( model.Email, model.Password, model.RememberMe, lockoutOnFailure: false); if (result.Succeeded) { return RedirectToAction("Index", "Home"); } ModelState.AddModelError(string.Empty, "Invalid login attempt."); } return View(model); } [HttpPost] public async Task<IActionResult> Logout() { await _signInManager.SignOutAsync(); return RedirectToAction("Index", "Home"); } } ``` 这段代码将处理用户注册、录和注销的逻辑。请注意,我们使用了一些视图模型,如 RegisterViewModel 和 LoginViewModel,这些模型将用于表单验证和数据绑定。 8. 创建一个名为“RegisterViewModel”的新模型,用于表单验证和数据绑定。以下是一个示例: ```csharp public class RegisterViewModel { [Required] [EmailAddress] [Display(Name = "Email")] public string Email { get; set; } [Required] [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 8)] [DataType(DataType.Password)] [Display(Name = "Password")] public string Password { get; set; } [DataType(DataType.Password)] [Display(Name = "Confirm password")] [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] public string ConfirmPassword { get; set; } } ``` 9. 创建一个名为“LoginViewModel”的新模型,用于表单验证和数据绑定。以下是一个示例: ```csharp public class LoginViewModel { [Required] [EmailAddress] public string Email { get; set; } [Required] [DataType(DataType.Password)] public string Password { get; set; } [Display(Name = "Remember me?")] public bool RememberMe { get; set; } } ``` 10. 最后,创建视图文件以呈现注册和录表单。例如,以下是一个简单的注册视图: ```html @model RegisterViewModel <h2>Register</h2> <form asp-action="Register" method="post"> <div asp-validation-summary="ModelOnly" class="text-danger"></div> <div class="form-group"> <label asp-for="Email"></label> <input asp-for="Email" class="form-control" /> <span asp-validation-for="Email" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="Password"></label> <input asp-for="Password" class="form-control" /> <span asp-validation-for="Password" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="ConfirmPassword"></label> <input asp-for="ConfirmPassword" class="form-control" /> <span asp-validation-for="ConfirmPassword" class="text-danger"></span> </div> <button type="submit" class="btn btn-primary">Register</button> </form> ``` 这只是一个简单的示例,你可以根据自己的需要对其进行修改。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值