MVC基本登陆与验证码功能实现
一、基本登陆实现与验证码功能实现,该功能是和spring.net功能集合使用的,因为后面要用到验证是否处于登陆状态
1. 先构建一个登陆页面
1 @{ 2 Layout = null; 3 } 4 <!DOCTYPE html> 5 <html> 6 <head> 7 <title>XX商城后台管理系统登录</title> 8 <script type="text/javascript"> 9 if (window.parent.window != window) { 10 window.top.location.href = "/Home/CheckLogin"; 11 } 12 </script> 13 <script src="~/Scripts/jquery-1.8.2.min.js" type="text/javascript"></script> 14 @* <script src="../../Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>*@ 15 <script src="~/Scripts/jquery.validate.min.js"></script> 16 @*<script src="../../Scripts/jquery.validate.min.js" type="text/javascript"></script>*@ 17 <script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script> @*ajax登录*@ 18 <script type="text/javascript"> 19 function changeCheckCode() { 20 //为图片加一个src参数,向其后追加一个1,比如现在是src=“a1”,点击一次就是a11 21 $("#img").attr("src", $("#img").attr("src") + 1); 22 } 23 function afterLogin(data) { 24 var serverData = data.split(':'); 25 if (serverData[0] == "ok") { 26 //页面跳转一下 27 window.location.href = "/Home/Index" 28 } else { 29 $("#errorMsg").css("display", "block"); 30 $("#errorMsg").text(serverData[1]); 31 changeCheckCode(); //让验证码切换一下 32 } 33 } 34 </script> 35 <style type="text/css"> 36 * { 37 padding: 0; 38 margin: 0; 39 } 40 body { 41 text-align: center;background: #4974A4; 42 } 43 #login { 44 width: 740px; margin: 0 auto;font-size: 12px; 45 } 46 #loginlogo { 47 width: 700px; height: 100px; overflow: hidden;background: url('/Content/Images/login/logo.png') no-repeat; margin-top: 50px; 48 } 49 #loginpanel { 50 width: 729px; 51 position: relative; 52 height: 300px; 53 } 54 .panel-h { 55 width: 729px; 56 height: 20px; 57 background: url('/Content/Images/login/panel-h.gif') no-repeat; 58 position: absolute; 59 top: 0px; 60 left: 0px; 61 z-index: 3; 62 } 63 .panel-f { 64 width: 729px; 65 height: 13px; 66 background: url('/Content/Images/login/panel-f.gif') no-repeat; 67 position: absolute; 68 bottom: 0px; 69 left: 0px; 70 z-index: 3; 71 } 72 .panel-c { 73 z-index: 2; 74 background: url('/Content/Images/login/panel-c.gif') repeat-y; 75 width: 729px; 76 height: 300px; 77 } 78 .panel-c-l { 79 position: absolute; 80 left: 60px; 81 top: 40px; 82 } 83 .panel-c-r { 84 position: absolute; 85 right: 20px; 86 top: 50px; 87 width: 222px; 88 line-height: 200%; 89 text-align: left; 90 } 91 .panel-c-l h3 { 92 color: #556A85; 93 margin-bottom: 10px; 94 } 95 .panel-c-l td { 96 padding: 7px; 97 } 98 .login-text { 99 height: 24px; 100 left: 24px; 101 border: 1px solid #e9e9e9; 102 background: #f9f9f9; 103 } 104 .login-text-focus { 105 border: 1px solid #E6BF73; 106 } 107 .login-btn { 108 width: 114px; 109 height: 29px; 110 color: #E9FFFF; 111 line-height: 29px; 112 background: url('/Content/Images/login/login-btn.gif') no-repeat; 113 border: none; 114 overflow: hidden; 115 cursor: pointer; 116 } 117 #txtUsername, #code, #txtPassword { 118 width: 191px; 119 } 120 #logincopyright { 121 text-align: center; 122 color: White; 123 margin-top: 50px; 124 } 125 a { 126 color: Black; 127 } 128 a:hover { 129 color: Red; 130 text-decoration: underline; 131 } 132 </style> 133 </head> 134 <body style="padding: 10px"> 135 <div id="login"> 136 <div id="loginlogo"> 137 </div> 138 <div id="loginpanel"> 139 <div class="panel-h"> 140 </div> 141 <div class="panel-c"> 142 <div class="panel-c-l"> @*请求地址,控制器名 参数为null 请求方式 返回函数 加载执行时动画 表单id的值 *@ 143 @using (Ajax.BeginForm("UserLogin", "Login", new { }, new AjaxOptions() { HttpMethod = "post", OnSuccess = "afterLogin", LoadingElementId = "div1" }, new { id = "loginForm" })) 144 { 145 <table cellpadding="0" cellspacing="0"> 146 <tbody> 147 <tr> 148 <td align="left" colspan="2"> 149 <h3> 150 请使用ItcastOA管理系统账号登录 151 </h3> 152 </td> 153 </tr> 154 <tr> 155 <td align="right"> 156 账号: 157 </td> 158 <td align="left"> 159 <input type="text" name="LoginCode" id="LoginCode" class="login-text" /> 160 </td> 161 </tr> 162 <tr> 163 <td align="right"> 164 密码: 165 </td> 166 <td align="left"> 167 <input type="password" name="LoginPwd" id="LoginPwd" value="123" class="login-text" /> 168 </td> 169 </tr> 170 <tr> 171 <td> 172 验证码: 173 </td> 174 <td align="left"> 175 <input type="text" class="login-text" id="code" name="vCode" value="1" /> 176 </td> 177 </tr> 178 <tr> 179 <td></td> 180 <td> 181 <img id="img" src="/Login/ShowValidateCode?id=1" style="float: left; height: 24px;" /> 182 <div style="float: left; margin-left: 5px; margin-top: 10px;"> 183 <a href="javascript:void(0)" onclick="changeCheckCode();return false;">看不清,换一张</a> 184 </div> 185 </td> 186 </tr> 187 <tr> 188 <td align="center" colspan="2"> 189 <input type="submit" id="btnLogin" value="登录" class="login-btn" /><span id="errorMsg" style="font-size:14px;color:red;display:none"></span> 190 <div id="div1" style="display:none">正在登录,请稍后....</div> 191 </td> 192 </tr> 193 </tbody> 194 </table> 195 } 196 </div> 197 <div class="panel-c-r"> 198 <p> 199 请从左侧输入登录账号和密码登录 200 </p> 201 <p> 202 如果遇到系统问题,请联系网络管理员。 203 </p> 204 <p> 205 如果没有账号,请联系网站管理员。 206 </p> 207 <p> 208 ...... 209 </p> 210 </div> 211 </div> 212 <div class="panel-f"> 213 </div> 214 </div> 215 <div id="logincopyright"> 216 Copyright ? 2015 itcast.com 217 </div> 218 </div> 219 </body> 220 </html>
2、 封装一个生成验证码的文件,放置在Common文件夹下,引用dll文件system.Drawing。
using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web; namespace Common { 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="context">要输出到的page对象</param> /// <param name="validateNum">验证码</param> public void CreateValidateGraphic(string validateCode, HttpContext context) //使用HttpContext必须引用system.web,是引入而不是导入 { 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); //输出图片流 context.Response.Clear(); context.Response.ContentType = "image/jpeg"; context.Response.BinaryWrite(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; } //C# MVC 升级版 /// <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(); } } } }
3. 后端代码实现完成用户登录与验证码功能实现。
1 using BLL; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Web; 6 using System.Web.Mvc; 7 namespace OA_MVC.Controllers 8 { 9 public class LoginController : Controller 10 { 11 // 12 // GET: /Login/ 13 14 public ActionResult Index() 15 { 16 return View(); 17 } 18 IBLL.IUserInfoService UserInfoService { get; set; } 19 #region 完成用户登录 20 public ActionResult UserLogin() 21 { 22 //判断验证码是否正确 23 string validateCode = Session["validateCode"] != null ? Session["validateCode"].ToString() : string.Empty; 24 if (string.IsNullOrEmpty(validateCode)) //如果等于null 25 { 26 return Content("no:验证码错误!!"); 27 } 28 Session["validateCode"] = null; 29 string txtCode = Request["vCode"]; 30 //如果验证码不相等 31 if (!validateCode.Equals(txtCode, StringComparison.InvariantCultureIgnoreCase)) 32 { 33 return Content("no:验证码错误!!"); 34 } 35 string userName = Request["LoginCode"]; 36 string userPwd = Request["LoginPwd"]; 37 var userInfo = UserInfoService.LoadEntities(u => u.UName == userName && u.UPwd == userPwd).FirstOrDefault();//根据用户名找用户 38 if (userInfo != null) 39 { 40 Session["userInfo"] = userInfo; 41 ////产生一个GUID值作为Memache的键. 42 //// System.Web.Script.Serialization.JavaScriptSerializer 43 //string sessionId = Guid.NewGuid().ToString(); 44 //Common.MemcacheHelper.Set(sessionId, Common.SerializeHelper.SerializeToString(userInfo) 45 // , DateTime.Now.AddMinutes(20));//将登录用户信息存储到Memcache中。 46 //Response.Cookies["sessionId"].Value = sessionId;//将Memcache的key以Cookie的形式返回给浏览器。 47 return Content("ok:登录成功"); 48 } 49 else 50 { 51 return Content("no:登录失败"); 52 } 53 } 54 #endregion 55 #region 显示验证码 56 public ActionResult ShowValidateCode() 57 { 58 Common.ValidateCode vliateCode = new Common.ValidateCode(); 59 string code = vliateCode.CreateValidateCode(4);//产生验证码,4位数的验证码 60 Session["validateCode"] = code; //存在session中进行校验 61 byte[] buffer = vliateCode.CreateValidateGraphic(code);//将验证码画到画布上. 62 return File(buffer, "image/jpeg"); //向浏览器返回一个文件 63 } 64 #endregion 65 } 66 }
4. config文件夹中的controllers.xml文件中,加入以下代码,作用是为该类中的UserInfoService属性赋值。 相关spring.net知识点请参考https://www.cnblogs.com/wangjinya/p/10706744.html
1 <object type="CZBK.ItcastOA.WebApp.Controllers.LoginController, CZBK.ItcastOA.WebApp" singleton="false" > 2 <property name="UserInfoService" ref="UserInfoService" /> 3 </object>
5. 方法过滤器,
5.1 新建一个base控制器,该控制器主要用来把执行过程从中间切割,让每一次执行,都会执行该方法,OnActionExecuting方法是提供的一个类,每次执行就会先执行该方法。
1 public class BaseController : Controller 2 { 3 // 4 // GET: /Base/ 5 6 /// <summary> 7 /// 方法过滤器,执行控制器中的方法之前先执行该方法。 8 /// </summary> 9 /// <param name="filterContext"></param> 10 protected override void OnActionExecuting(ActionExecutingContext filterContext) 11 { 12 base.OnActionExecuting(filterContext); 13 if (Session["userInfo"] == null) 14 { 15 // filterContext.HttpContext.Response.Redirect("/Login/Index");
// 因为在返回的切片处理的过程中,之前的函数必须返回一个Result类型的试图过去,所以,以上方法不能满足,只能使用以下方法 16 //返回一个ActionResult类型的Redirect,继承该类的类就不会去执行本身的Redirect,需要使用下面的方法,而不是上面的方法 17 filterContext.Result = Redirect("/Login/Index"); 18 } 19 } 20 } 21 }
5.2 让每一个控制器继承该控制器的类名
1 public class LoginController : BaseController //Controller 2 { 3 // 4 // GET: /Login/ 5 6 public ActionResult Index() 7 { 8 return View(); 9 } 10 }