几种登录功能的实现方法
1.建模型,并生成相应的数据表
Feature1:建立用户模型,并生成相应的数据表
(1)新建mvc4项目,选择基本模板
(2)新建模型类User
namespace LoginExample.Models { public class User { public int UserId { get; set; } public string LoginName { get; set; } public string Password { get; set; } public SRole SRole { get; set; } } public enum SRole { 学生,教师,管理员 } }
(3)新建数据上下文类
namespace LoginExample.Models { public class LoginExampleDB:DbContext { public DbSet<User> Users { get; set; } } }
(4)修改web.config中连接字符串
<connectionStrings> <add name="LoginExampleDB" providerName="System.Data.SqlClient" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;Initial Catalog=LoginExampleDB;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\LoginExampleDB.mdf" /> </connectionStrings>
(5)数据迁移
2.[Authorize]过滤器使用
Feautre2:设计登录功能实现,并且用户需要授权认证
(1)已知模型User类,并且已有角色学生、老师、管理员,代码参考Feature1
(2)添加Account控制器,用于控制账号管理
(3)在Account控制器中,添加2个Login动作,读取数据库比对账号、密码、角色
public class AccountController : Controller { LoginExampleDB db = new LoginExampleDB(); public ActionResult Login() { return View(); } [HttpPost] public ActionResult Login(User user) { if(ModelState.IsValid) { var dbUser = db.Users.Where(u => u.LoginName == user.LoginName && u.Password == user.Password).FirstOrDefault; if(dbUser!=null) { FormsAuthentication.SetAuthCookie(user.LoginName, false); return RedirectToAction("Index", "Home"); } else
{
ModelState.AddModelError("", "用户或密码错误");
} } return View(User); } }
(4)添加Login视图
@model LoginExample.Models.User @{ ViewBag.Title = "Login"; } <h2>欢迎登录</h2> @using (Html.BeginForm()) { <p>用户名:@Html.EditorFor(u=>u.LoginName)</p> <p>密码:@Html.PasswordFor(u=>u.Password)</p> <input type="submit" value="登录" /> }
(5)添加Home控制器,用于处理登录后的访问页面
[Authorize] public class HomeController : Controller { // GET: Home public ActionResult Index() { return View(); } }
(6)在Home控制器中,添加Index动作,并在视图中给出友好信息“XX,你好!”
@{ ViewBag.Title = "Index"; } <h2>首页</h2> <p>你好,@User.Identity.Name</p>
3.更改授权过滤器,[Authorize(Users="admin")]
Feature3:只有用户名为admin可以访问,其他用户不能访问
(1)在Account控制器的Login动作中设置跳转到Admin\Index
return RedirectToAction("Index", "Admin");
(2)新建Admin控制器,在控制器上加授权过滤器
[Authorize(Users ="admin")] public class AdminController : Controller {
4.更改授权过滤器,[Authorize(Roles="管理员")]
Feature4:只有角色为管理员才可以访问,其他用户不能访问
(1)修改Login动作代码
[HttpPost] public ActionResult Login(Administrator admin) { var user=db.Administrators.Where(a=>a.UserName==admin.UserName && a.Password==admin.Password).FirstOrDefault(); if(ModelState.IsValid)
{
if (user != null) { //创建一个新的票据,将用户的名字记入ticket的userdata
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
1, user.LoginName, DateTime.Now, DateTime.Now.AddMinutes(20),
false, user.SRole.ToString());
//将票据加密
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
//将加密后的票据保存为cookie
System.Web.HttpCookie authCookie = new System.Web.HttpCookie
(FormsAuthentication.FormsCookieName, encryptedTicket);
authCookie.HttpOnly = true; //客户端的js不能访问cookie
//使用加入了userdata的新cookie
System.Web.HttpContext.Current.Response.Cookies.Add(authCookie);
return RedirectToAction("Index", "Admin"); }
else
{
ModelState.AddModelError("", "您输入的账号或密码错误");
}
return View(); }
(2)在global.asax.cs文件中,添加方法
protected void Application_AuthorizeRequest(object sender, System.EventArgs e) { HttpApplication App = (HttpApplication)sender; HttpContext Ctx = App.Context; //获取本次Http请求相关的HttpContext对象 if (Ctx.Request.IsAuthenticated == true) //验证过的用户才进行role的处理 { FormsIdentity Id = (FormsIdentity)Ctx.User.Identity; FormsAuthenticationTicket Ticket = Id.Ticket; //取得身份验证票 string[] Roles = Ticket.UserData.Split(','); //将身份验证票中的role数据转成字符串数组 Ctx.User = new GenericPrincipal(Id, Roles); //将原有的Identity加上角色信息新建一个GenericPrincipal表示当前用户,这样当前用户就拥有了role信息 } }
(3)修改Admin控制器上的授权过滤器代码
[Authorize(Roles="管理员")] public class AdminController:Controller { ... }
5.Feature5:将User类拆分,变成Admin、Student、Teacher类,登录如何修改?
(1)增加Admin、Student、Teacher类
public class Admin { public int AdminId { get; set; } public string LoginName { get; set; } public string Password { get; set; } public SRole SRole { get; set; } public string RealName { get; set; } public string Phone { get; set; } public string Email { get; set; } public string QQ { get; set; } public string Department { get; set; } public string Location { get; set; } }
public class Student { public int StudentId { get; set; } public string LoginName { get; set; } public string Password { get; set; } public SRole SRole { get; set; } public string RealName { get; set; } public string Phone { get; set; } public string Email { get; set; } public string QQ { get; set; } public string Department { get; set; } public string Location { get; set; } //以下是不同的属性 public string StuNo { get; set; } public string SClass { get; set; } }
public class Teacher { public int TeacherId { get; set; } public string LoginName { get; set; } public string Password { get; set; } public SRole SRole { get; set; } public string RealName { get; set; } public string Phone { get; set; } public string Email { get; set; } public string QQ { get; set; } public string Department { get; set; } public string Location { get; set; } //以下是不同的属性 public string Position { get; set; } public string TechTitle { get; set; } }
(2)将User类改为视图模型类
public class VMUser
{
[Required(ErrorMessage="用户名不能为空")]
public string LoginName { get; set; }
[Required(ErrorMessage = "密码不能为空")]
public string Password { get; set; }
[Required]
public SRole SRole { get; set; }
[Required(ErrorMessage = "验证码不能为空")]
public string Code { get; set; }
}
public enum SRole
{
学生, 教师, 管理员
}
(3)修改Account控制器中的Login动作
[HttpPost] [ValidateAntiForgeryToken] public ActionResult Login(VMUser user) { string controllerName = ""; if (ModelState.IsValid) { if(CheckUser(user)) { SaveUserInCookie(user); switch (user.SRole.ToString()) { case ("学生"): controllerName = "Student"; break; case ("教师"): controllerName = "Teacher"; break; case ("管理员"): controllerName = "Admin"; break; } return RedirectToAction("Index", controllerName); } else { ModelState.AddModelError("", "您输入的账号或密码错误"); } } return View(user); } private bool CheckUser(VMUser user) {
bool isPass=false;
Object dbUser=null;
if (user.SRole.ToString() == "学生")
{
dbUser = db.Students.Where(u => u.PersonInfo.LoginName == user.LoginName && u.PersonInfo.Password == user.Password).FirstOrDefault();
}
else if (user.SRole.ToString() == "教师")
{
dbUser = db.Teachers.Where(u => u.PersonInfo.LoginName == user.LoginName && u.PersonInfo.Password == user.Password).FirstOrDefault();
}
else if (user.SRole.ToString() == "管理员")
{
dbUser = db.Admins.Where(u => u.PersonInfo.LoginName == user.LoginName && u.PersonInfo.Password == user.Password).FirstOrDefault();
}
if(dbUser!=null)
{
isPass = true;
}
return isPass; } private void SaveUserInCookie(VMUser user) { //创建一个新的票据,将用户的名字记入ticket的userdata FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket( 1, user.LoginName, DateTime.Now, DateTime.Now.AddMinutes(20), false, user.SRole.ToString()); //将票据加密 string encryptedTicket = FormsAuthentication.Encrypt(authTicket); //将加密后的票据保存为cookie System.Web.HttpCookie authCookie = new System.Web.HttpCookie (FormsAuthentication.FormsCookieName, encryptedTicket); authCookie.HttpOnly = true; //客户端的js不能访问cookie //使用加入了userdata的新cookie System.Web.HttpContext.Current.Response.Cookies.Add(authCookie); }
(4)修改Login视图代码
@model LoginSystem.Models.VMUser @{ ViewBag.Title = "Login"; } <h2>欢迎登录</h2> @using (Html.BeginForm()) { @Html.AntiForgeryToken() <p>用户名:@Html.EditorFor(u=>u.LoginName)</p> <p>密码:@Html.PasswordFor(u=>u.Password)</p> <p>身份: @Html.RadioButtonFor(u=>u.SRole,0) <span>学生</span> @Html.RadioButtonFor(u=>u.SRole,1) <span>教师</span> @Html.RadioButtonFor(u=>u.SRole,2) <span>管理员</span> </p> <input type="submit" value="登录" /> }
6.Feature6:将Admin、Student、Teacher类的基本信息类统一为PersonInfo类
(1)将基本信息放入PersonInfo模型类中,并改写Admin、Student和Teacher类
namespace LoginSystem.Models { public class PersonInfo { public int PersonInfoId { get; set; } public string LoginName { get; set; } [DataType(DataType.Password)] public string Password { get; set; } public SRole SRole { get; set; } public string RealName { get; set; } public string Phone { get; set; } public string Email { get; set; } public string QQ { get; set; } public string Department { get; set; } public string Location { get; set; } } }
public class Admin { public int AdminId { get; set; } public PersonInfo PersonInfo { get; set; } }
public class Student { public int StudentId { get; set; } public PersonInfo PersonInfo { get; set; } //以下是不同的属性 public string StuNo { get; set; } public string SClass { get; set; } }
public class Teacher { public int TeacherId { get; set; } public PersonInfo PersonInfo { get; set; } //以下是不同的属性 public string Position { get; set; } public string TechTitle { get; set; } }
(2)修改Account控制器中的CheckUser方法
private bool CheckUser(VMUser user) { bool isPass=false; Object dbUser=null; if (user.SRole.ToString() == "学生") { dbUser = db.Students.Where(u => u.PersonInfo.LoginName == user.LoginName && u.PersonInfo.Password == user.Password).FirstOrDefault(); } else if (user.SRole.ToString() == "教师") { dbUser = db.Teachers.Where(u => u.PersonInfo.LoginName == user.LoginName && u.PersonInfo.Password == user.Password).FirstOrDefault(); } else if (user.SRole.ToString() == "管理员") { dbUser = db.Admins.Where(u => u.PersonInfo.LoginName == user.LoginName && u.PersonInfo.Password == user.Password).FirstOrDefault(); } if(dbUser!=null) { isPass = true; } return isPass; }
7.Feature7:添加验证码
(1)在项目根目录下增加文件夹Utilities,并增加文件ValidateCode.cs,代码如下
namespace GraduationSystem.WebUI.Utilities.ValidateCode { /// <summary> /// 生成验证码的类 /// </summary> public class ValidateCode { public ValidateCode() { } /// <summary> /// 验证码的最大长度 /// </summary> public int MaxLength { get { return 10; } } /// <summary> /// 验证码的最小长度 /// </summary> public int MinLength { get { return 1; } } /// <summary> /// 生成验证码 /// </summary> /// <param name="length">指定验证码的长度</param> /// <returns></returns> public string CreateValidateCode(int length) { int[] randMembers = new int[length]; int[] validateNums = new int[length]; string validateNumberStr = ""; //生成起始序列值 int seekSeek = unchecked((int)DateTime.Now.Ticks); Random seekRand = new Random(seekSeek); int beginSeek = (int)seekRand.Next(0, Int32.MaxValue - length * 10000); int[] seeks = new int[length]; for (int i = 0; i < length; i++) { beginSeek += 10000; seeks[i] = beginSeek; } //生成随机数字 for (int i = 0; i < length; i++) { Random rand = new Random(seeks[i]); int pownum = 1 * (int)Math.Pow(10, length); randMembers[i] = rand.Next(pownum, Int32.MaxValue); } //抽取随机数字 for (int i = 0; i < length; i++) { string numStr = randMembers[i].ToString(); int numLength = numStr.Length; Random rand = new Random(); int numPosition = rand.Next(0, numLength - 1); validateNums[i] = Int32.Parse(numStr.Substring(numPosition, 1)); } //生成验证码 for (int i = 0; i < length; i++) { validateNumberStr += validateNums[i].ToString(); } return validateNumberStr; } /// <summary> /// 创建验证码的图片 /// </summary> /// <param name="containsPage">要输出到的page对象</param> /// <param name="validateNum">验证码</param> public byte[] CreateValidateGraphic(string validateCode) { Bitmap image = new Bitmap((int)Math.Ceiling(validateCode.Length * 12.0), 22); Graphics g = Graphics.FromImage(image); try { //生成随机生成器 Random random = new Random(); //清空图片背景色 g.Clear(Color.White); //画图片的干扰线 for (int i = 0; i < 25; i++) { int x1 = random.Next(image.Width); int x2 = random.Next(image.Width); int y1 = random.Next(image.Height); int y2 = random.Next(image.Height); g.DrawLine(new Pen(Color.Silver), x1, y1, x2, y2); } Font font = new Font("Arial", 12, (FontStyle.Bold | FontStyle.Italic)); LinearGradientBrush brush = new LinearGradientBrush(new Rectangle(0, 0, image.Width, image.Height), Color.Blue, Color.DarkRed, 1.2f, true); g.DrawString(validateCode, font, brush, 3, 2); //画图片的前景干扰点 for (int i = 0; i < 100; i++) { int x = random.Next(image.Width); int y = random.Next(image.Height); image.SetPixel(x, y, Color.FromArgb(random.Next())); } //画图片的边框线 g.DrawRectangle(new Pen(Color.Silver), 0, 0, image.Width - 1, image.Height - 1); //保存图片数据 MemoryStream stream = new MemoryStream(); image.Save(stream, ImageFormat.Jpeg); //输出图片流 return stream.ToArray(); } finally { g.Dispose(); image.Dispose(); } } /// <summary> /// 得到验证码图片的长度 /// </summary> /// <param name="validateNumLength">验证码的长度</param> /// <returns></returns> public static int GetImageWidth(int validateNumLength) { return (int)(validateNumLength * 12.0); } /// <summary> /// 得到验证码的高度 /// </summary> /// <returns></returns> public static double GetImageHeight() { return 22.5; } } }
(2)在Account控制器中,增加方法调用ValidateCode
public ActionResult GetValidateCode() { ValidateCode vCode = new ValidateCode(); string code = vCode.CreateValidateCode(5); Session["ValidateCode"] = code; byte[] bytes = vCode.CreateValidateGraphic(code); return File(bytes, @"image/jpeg"); }
(3)在Login视图中,增加验证码图片
@using (Html.BeginForm()) { @Html.ValidationSummary() @Html.AntiForgeryToken() <p>用户名:@Html.EditorFor(u=>u.LoginName)</p> <p>密码:@Html.PasswordFor(u=>u.Password)</p> <p>身份: @Html.RadioButtonFor(u=>u.SRole,0) <span>学生</span> @Html.RadioButtonFor(u=>u.SRole,1) <span>教师</span> @Html.RadioButtonFor(u=>u.SRole,2) <span>管理员</span> </p> <p> <label>验 证 码:</label> @Html.EditorFor(model => model.Code) <img id="valiCode" style="cursor: pointer;margin-bottom:-5px;" src="\Account\GetValidateCode" alt="验证码" /> </p> <input type="submit" value="登录" /> }
(4)在Acoount控制器的Login方法中增加验证码的判断
[HttpPost] [ValidateAntiForgeryToken] public ActionResult Login(VMUser user) { string controllerName = ""; if (Session["ValidateCode"].ToString() != user.Code) { ModelState.AddModelError("", "验证码错误"); } else if (ModelState.IsValid) {。。。。