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)
            {。。。。