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