mvc示例项目之二----登录功能实现
写在前面的
本节用登录功能介绍一个Controller及View层的编写。.net的mvc框架将每个可调用函数是Controller当中的一个返回值为ActionResult函数。ActionResult是一个父类,一般来说最常用的返回值为ViewResult、JsonResult、FileResult。ViewResult返回一个页面,JsonResult返回一个Json对象(一般用于ajax调用),FileResult返回一个文件(图片等)。
图一、ActionResult类继承关系
本博客系列通过两个Controller及有限的几个View页面将这三个ActionResult返回类型都进行介绍。
由于侧重于介绍mvc,所以Ajax、Json等基本概念就不做赘述,不了解这些概念的朋友们可以百度或者必应。
首先,将对bs系统的大门——登录页面进行介绍。
登录功能简介
登录功能是一个bs系统的门户,本节介绍如何生成认证码图片、如何验证跳转。下一节介绍如何使用Filter权限认证。
登录实现
Mvc3.0采用了Razor模板,可以说写前端代码很是明晰舒服。如下是View页面代码。
@model Entity.Admin @{ Layout = null; } <html> <head> <title>登陆网站</title> <meta http-equiv="Content-Type" content="text/html; charset=gb2312"> <style type="text/css"> INPUT { border-right: #000000 1px solid; border-top: #000000 1px solid; border-left: #000000 1px solid; border-bottom: #000000 1px solid; height: 20px; } TD { font-size: 12px; } .inll { border-right: #ffffff; border-top: #ffffff; border-left: #ffffff; border-bottom: #ffffff; } .STYLE1 { color: #FFFFFF; } .STYLE3 { color: #FFFFFF; font-weight: bold; } </style> <script src="@Url.Content("~/Scripts/jquery-1.7.2.min.js")" type="text/javascript"></script> <script type="text/javascript"> function CheckForm() { if (document.Login.UserName.value == "") { alert("请输入用户名!"); document.Login.UserName.focus(); return false; } if (document.Login.Password.value == "") { alert("请输入密码!"); document.Login.Password.focus(); return false; } if (document.Login.CheckCode.value == "") { alert("请输入您的验证码!"); document.Login.CheckCode.focus(); return (false); } return true; } function Check() { if(!CheckForm()){ return false; } $.post("@Url.Action("Loginin")", { UserName: $("#UserName").val(),Password:$("#Password").val(), CheckCode:$("#CheckCode").val()},function(data){ if(data.flag){//如果验证成功,则跳转 window.location.href=data.msg; } else{ alert(data.msg);//弹出失败信息 } }); } function RefreshImage() { var el =document.getElementById("codeImg"); el.src=el.src+'?';//这个特别重要 } </script> </head> <body bgcolor="#FFFFFF" background="" leftmargin="0" topmargin="0" marginwidth="0" marginheight="0"> <table width="100%" border="0" align="center" cellpadding="0" cellspacing="0"> <tr> <td height="308" valign="middle"> <table cellspacing="0" cellpadding="0" width="100%" align="center" bgcolor="#ffffff" border="0"> <tbody> <tr> <td height="182" align="center" valign="bottom"> </td> </tr> <tr> <td height="8" valign="bottom"> </td> </tr> <tr> <TD height="160" align="center" valign="bottom" background="@Url.Content("~/Content/images/line.gif")"> <table width="59%" align="center" border="0"> <tbody> <tr> <td width="32%" height="183" align="center" valign="middle"> <img src="@Url.Content("~/Content/images/Login_pic.gif")" width="130" height="106"> </td> <td width="3%" valign="top"> <img src="@Url.Content("~/Content/images/Login_line.gif")" width="2" height="150"> </td> <td width="65%"> <form name="Login" method="post" target="_parent"> <table width="100%" border="0" align="center" cellpadding="0" cellspacing="0"> <tbody> <tr> <td height="26" colspan="2" nowrap> <img src="@Url.Content("~/Content/images/Login_tit.gif")" width="370" height="42"> </td> </tr> <tr> <td width="31%" height="26" align="right" nowrap> <span class="STYLE3">用户名:</span> </td> <td width="69%" height="26" nowrap> <input name="UserName" type="text" id="UserName" maxlength="20" style="width: 160px; border-style: solid; border-width: 1; padding-left: 4; padding-right: 4; padding-top: 1; padding-bottom: 1" onmouseover="this.style.background='#E1F4EE';" onmouseout="this.style.background='#FFFFFF'" onfocus="this.select(); "> </td> </tr> <tr> <td height="26" align="right" nowrap class="STYLE3"> 密 码: </td> <td nowrap height="26"> <input name="Password" id="Password" type="Password" maxlength="20" style="width: 160px; border-style: solid; border-width: 1; padding-left: 4; padding-right: 4; padding-top: 1; padding-bottom: 1" onmouseover="this.style.background='#E1F4EE';" onmouseout="this.style.background='#FFFFFF'" onfocus="this.select(); "> </td> </tr> <tr> <td height="26" align="right" nowrap class="STYLE3"> 验证码: </td> <td nowrap height="26"> <input name="CheckCode" id="CheckCode" size="6" maxlength="4" style="border-style: solid; border-width: 1; padding-left: 4; padding-right: 4; padding-top: 1; padding-bottom: 1" onmouseover="this.style.background='#E1F4EE';" onmouseout="this.style.background='#FFFFFF'" onfocus="this.select(); "> <img src="@Url.Action("GetValidateCode")" id="codeImg" onclick="RefreshImage()" alt="点击重刷新" /> </td> </tr> <tr> <td height="26" colspan="2" align="center"> <input type="button" name="Submit" onclick="Check();" value=" 确 认 " style="font-size: 9pt; height: 19; width: 60; color: #000000; background-color: #E1F4EE; border: 1 solid #E1F4EE" onmouseover="this.style.backgroundColor='#ffffff'" onmouseout="this.style.backgroundColor='#E1F4EE'"> <input name="reset" type="reset" id="reset" value=" 清 除 " style="font-size: 9pt; height: 19; width: 60; color: #000000; background-color: #E1F4EE; border: 1 solid #E1F4EE" onmouseover="this.style.backgroundColor='#ffffff'" onmouseout="this.style.backgroundColor='#E1F4EE'"> </td> </tr> </tbody> </table> </form> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> </td> </tr> <tr> <td height="20" align="center"> </td> </tr> </table> </body> </html>
接收用户登录请求的函数叫做Login(),位于Home控制器下。代码如下:
public ActionResult Login()
{
return View();
}
细心的读者会发现,只有一句。是的,只返回一个ViewResult,然后请求页面即展现出来。
由于采用Ajax提交,所以提交按钮采用Button事件,如果采用Submit控件需要重写Onsubmit方法。由于前端用Jquery实现Ajax提交,所以代码不是很繁琐。以下是Jquery ajax提交方式:
$.post("@Url.Action("Loginin")", { UserName: $("#UserName").val(),Password:$("#Password").val(), CheckCode:$("#CheckCode").val()},function(data){
if(data.flag){//验证成功跳转
window.location.href=data.msg;
}
else{
alert(data.msg);//弹出失败信息
}
});
上述代码发送请求及返回请求都是Json字符串。由于两个方法位于同一个控制器下,所以在view页面中填写地址时只需要填写Url.Action(“actionname”)即可。如果不在同一个控制器下,则需要填写Url.Action(“ActionName”,”ControllerName”)方可。后台的验证代码如下:
public ActionResult Loginin(Admin admin, string CheckCode) { object sessionCodeObj= Session["ValidateCode"];//获取验证码 string sessionCode=(sessionCodeObj==null?string.Empty:sessionCodeObj.ToString()); if (!CheckCode.Equals(sessionCode))//如果验证码输入错误 { return Json(new { flag = false, msg = "验证码输入错误!" }, JsonRequestBehavior.AllowGet); } Admin old = EntityDMHelper.GetAdminByName(admin.UserName);//通过用户名获取用户实体 if (old == null) { return Json(new { flag = false, msg = "不存在该用户!" }, JsonRequestBehavior.AllowGet); } if (!VerifyMD5(admin.Password, old.Password))//验证用户密码 { return Json(new { flag = false, msg = "密码错误!" }, JsonRequestBehavior.AllowGet); } FormsAuthentication.SetAuthCookie(admin.UserName, false);//添加认证信息 return Json(new { flag = true, msg = Url.Action("GetList", "Article") }, JsonRequestBehavior.AllowGet); } private string MD5(string str) { return FormsAuthentication.HashPasswordForStoringInConfigFile(str, "MD5").ToString(); } private bool VerifyMD5(string str, string md5str) { return MD5(str).Equals(md5str); }
上述代码返回的是JsonResult。可以比照参数,看看前后台如何交互。那么验证码生成的代码又是如何呢?
验证码的生成
public ActionResult GetValidateCode()
{
ValidateCode vCode = new ValidateCode();
string code = vCode.CreateValidateCode(4);
Session["ValidateCode"] = code;//插入session
byte[] bytes = vCode.CreateValidateGraphic(code);//生成图片
return File(bytes, @"image/jpeg");
}
在验证码生成时,将验证码字符串插入到session中,同时返回一个img文件。那么前端如何接收呢?
function RefreshImage()//刷新验证码
{
var el =document.getElementById("codeImg");
el.src=el.src+'?';//这个特别重要
}
<img src="@Url.Action("GetValidateCode")" id="codeImg" onclick="RefreshImage()" alt="点击重刷新" />
当点击图片时,可以刷新图片,防止session过期。
验证码图片类
下面是验证码图片类:
using System; using System.Drawing; using System.Drawing.Imaging; using System.Web.UI; using System.Drawing.Drawing2D; using System.IO; namespace HaiLiang.Common { /// <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; } } }
说实话验证码是从网上找到的。让我们感谢原创者及不断的复制者们。
图二、登录页面局部
图三、登录后页面
如此,就简单的实现了登录功能。可以看出代码的优雅。
好了,本节至此结束。下节我们看看如何用Filter简单验证登录身份。

浙公网安备 33010602011771号