zoukankan      html  css  js  c++  java
  • 31、三层架构、AJAX+FormsAuthentication实现登陆

    三层架构

    前段时间公司要求修改一个网站,打开后我疯了,一层没有都是调用的DB接口,遍地的SQL语句,非常杂乱。

    什么是三层架构?

    三层架构是将整个项目划分为三个层次:表现层、业务逻辑层、数据访问层。目的为了高内聚低耦合思想。

    三层结构

    表现层(UI):接受用户请求,数据的返回呈现。

    业务逻辑层(BLL ):用来处理业务逻辑,处理用户提交的数据。

    数据访问层(DAL):用来与数据库进行交互,处理增、删、改、差。

    实体类对象(Model):用来存储实体类。

    三层关系

    UI表现层:接收用户输入的数据,并传递给业务逻辑层。

    BLL业务逻辑层:把接收到的数据传递给数据访问层,并返回结果给UI层。

    DAL数据访问层:负责与数据库进行交互,并将结果返回给BLL层。

    什么时候需要分层?

    当项目过大的时候可以分层开发,这样可以每个人负责的不同,共同进行开发。如果一个项目非常小的话,独立开发可以不分层。

    操作步骤:

    1、创建结构

    新增三个类库分别是:BLL、DAL、Model,并建立一个UI层(winform 或 webform 或 MVC项目)设置启动项为UI层

    这里随个人喜欢可以再加一个Common层,负责处理其他常用方法。

    2、引用关系

    DAL要用到Model,BLL要用到DAL、CL和Model,UI要用到BLL、Model和CL。相互引用即可。

    实现登陆

    登陆是所有系统的入口,相信大家一般都用session,本例使用FormsAuthentication微软提供的身份认证,存储在cookie中。

    假设有如下管理员表:

    mif_id:唯一标识,lever等级,usernmae,psw账号密码,trueName姓名,createTime创建日期,isLock是否锁定,Power权限。

    编写实体类

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 
     6 namespace Model
     7 {
     8     /// <summary>
     9     /// 管理员实体类
    10     /// </summary>
    11     public class ManagerInfo
    12     {
    13         /// <summary>
    14         /// 标识ID
    15         /// </summary>
    16         public int mif_id { get; set; }
    17         /// <summary>
    18         /// 暂时没用
    19         /// </summary>
    20         public int mif_pid { get; set; }
    21         /// <summary>
    22         /// 管理员等级
    23         /// </summary>
    24         public int mif_lever { get; set; }
    25         /// <summary>
    26         /// 账号
    27         /// </summary>
    28         public string mif_userName { get; set; }
    29         /// <summary>
    30         /// 密码
    31         /// </summary>
    32         public string mif_psw { get; set; }
    33         /// <summary>
    34         /// 姓名
    35         /// </summary>
    36         public string mif_trueName { get; set; }
    37         /// <summary>
    38         /// 创建时间
    39         /// </summary>
    40         public DateTime mif_createTime { get; set; }
    41         /// <summary>
    42         /// 是否锁定
    43         /// </summary>
    44         public bool mif_isLock { get; set; }
    45         /// <summary>
    46         /// 权限
    47         /// </summary>
    48         public string mif_power { get; set; }
    49     }
    50 }
    ManagerInfo.cs

    习惯性编写完Model重新生成下Model层,检查是否有错误。

    编写数据访问层

    引入sqlHelper文件(上一文章中找),修改UI中的web.config添加数据库连接字符串,并在sqlHelper中修改相关名称,注意引入System.configuration.dll。

    编写操作ManagerInfo的数据访问类

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using Model;
     6 using System.Data.SqlClient;
     7 
     8 namespace DAL
     9 {
    10     /// <summary>
    11     /// 管理员数据访问类
    12     /// </summary>
    13     public class ManagerInfoDal
    14     {
    15         /// <summary>
    16         /// 通过账号查找
    17         /// </summary>
    18         /// <param name="userName"></param>
    19         /// <returns></returns>
    20         public static ManagerInfo row(string userName)
    21         {
    22             string sql = "select mif_id,mif_lever,mif_userName,mif_psw,mif_trueName,mif_createTime,mif_isLock from managerInfo where mif_userName = @uid";
    23             var v = new ManagerInfo();
    24             using (var dr = SQLHelper.ExecuteReader(sql, new SqlParameter("@uid", userName)))
    25             {
    26                 if (dr.Read())
    27                 {
    28                     v.mif_id = Convert.ToInt32(dr["mif_id"]);
    29                     v.mif_lever = Convert.ToInt32(dr["mif_lever"]);
    30                     v.mif_userName = dr["mif_userName"].ToString();
    31                     v.mif_psw = dr["mif_psw"].ToString();
    32                     v.mif_trueName = dr["mif_trueName"].ToString();
    33                     v.mif_createTime = Convert.ToDateTime(dr["mif_createTime"]);
    34                     v.mif_isLock = Convert.ToBoolean(dr["mif_isLock"]);
    35                 }
    36             }
    37             return v;
    38         }
    39     }
    40 }
    ManagerInfoDal.cs

    编写业务逻辑层

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using DAL;
     6 using System.Web.Security;
     7 using System.Web;
     8 using CL;
     9 using Model;
    10 
    11 namespace BLL
    12 {
    13     /// <summary>
    14     /// 管理员
    15     /// </summary>
    16     public class ManagerInfoBll
    17     {
    18         /// <summary>
    19         /// 登陆
    20         /// </summary>
    21         /// <param name="userName"></param>
    22         /// <param name="passWord"></param>
    23         /// <param name="remember">是否记住</param>
    24         /// <returns></returns>
    25         public static string login(string userName, string passWord, string remember)
    26         {
    27             var v = ManagerInfoDal.row(userName);
    28             if (v.mif_id > 0)
    29             {
    30                 if (v.mif_isLock == false)
    31                 {
    32                     if (v.mif_psw.Equals(createMD5.getMD5(passWord)))
    33                     {
    34                         var expires = DateTime.Now.AddMinutes(20);
    35                         if (remember.Equals("on"))
    36                         {
    37                             expires = DateTime.Now.AddDays(8);
    38                         }
    39                         //将登陆的用户存储在Ticket中
    40                         var ticket = new FormsAuthenticationTicket(0, userName, DateTime.Now, expires, true, userName);
    41                         //使用Encrypt方法加密Ticket,并存储在cookie中
    42                         var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket));
    43                         //防止浏览器攻击窃取、伪造cookie信息
    44                         cookie.HttpOnly = true;
    45                         cookie.Expires = expires;
    46                         HttpContext.Current.Response.Cookies.Add(cookie);
    47                         return "0";
    48                     }
    49                     return "1";
    50                 }
    51                 return "2";
    52             }
    53             return "3";
    54         }
    55         public static ManagerInfo row(string userName)
    56         {
    57             return ManagerInfoDal.row(userName);
    58         }
    59         /// <summary>
    60         /// 查询权限(通过数字查询名字)
    61         /// </summary>
    62         /// <param name="userRole">权限数字</param>
    63         /// <returns></returns>
    64         public static string getRole(int userRole)
    65         {
    66             switch (userRole)
    67             {
    68                 case 0:
    69                     return "编辑";
    70                 case 1:
    71                     return "管理员";
    72                 case 2:
    73                     return "系统";
    74                 default:
    75                     return "暂无";
    76             }
    77         }
    78     }
    79 }
    ManagerInfoBll.cs

    管理员等级这里建议写成枚举,本人较懒。

    FormsAuthenticationTicket这个东西比传统的session和cookie的好处就是 可以任意目录设置他的访问权限,如果没有登陆直接跳出到登陆页面。而不用每个页面一开始都认证一番~

    还有 cookie.HttpOnly 在使用cookie时这一项最好设置一下,否则可能会客户端模拟cookie进行攻击。

    编写通用层

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Security.Cryptography;
     5 using System.Text;
     6 
     7 namespace CL
     8 {
     9     public class createMD5
    10     {
    11         public static string getMD5(string str)
    12         {
    13             var md5 = MD5.Create();
    14             var buffer = Encoding.Default.GetBytes(str);
    15             var mdbuffer = md5.ComputeHash(buffer);
    16             StringBuilder result = new StringBuilder();
    17             for (int i = 0; i < mdbuffer.Length; i++)
    18             {
    19                 result.Append(mdbuffer[i].ToString("x2"));
    20             }
    21             return result.ToString();
    22         }
    23     }
    24 }
    createMD5

    生成MD5的代码,可不用。

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Drawing;
     4 using System.Drawing.Drawing2D;
     5 using System.Drawing.Imaging;
     6 using System.IO;
     7 using System.Linq;
     8 using System.Text;
     9 using System.Web;
    10 
    11 namespace CL
    12 {
    13     public static class createVlidate
    14     {
    15         /// <summary>
    16         /// 字符
    17         /// </summary>
    18         /// <param name="len">几位</param>
    19         /// <returns></returns>
    20         public static string validation(int cd)
    21         {
    22             var ran = new Random();
    23             int num, tem;
    24             string rtuStr = "";
    25             for (int i = 0; i < cd; i++)
    26             {
    27                 num = ran.Next();
    28                 if (i % 2 == 1)
    29                     tem = num % 10 + '0'; //数字
    30                 else
    31                     tem = num % 26 + 'A'; //字母
    32                 rtuStr += Convert.ToChar(tem).ToString();
    33             }
    34             //写入cookie
    35             HttpCookie cookie = new HttpCookie("check");
    36             cookie.Value = rtuStr.ToLower();
    37             HttpContext.Current.Response.Cookies.Add(cookie);
    38             return rtuStr;
    39         }
    40 
    41         /// <summary>
    42         /// 生成图像
    43         /// </summary>
    44         /// <param name="check">字符</param>
    45         public static byte[] drawImg(string check)
    46         {
    47             Bitmap img = new Bitmap(90, 34);
    48             var ht = Graphics.FromImage(img);
    49             ht.Clear(Color.White);
    50             ht.DrawLine(new Pen(Color.SpringGreen), 1, 1, 90, 34);
    51             Font font = new Font("微软雅黑", 20, FontStyle.Bold);
    52             var jianbian = new LinearGradientBrush(new Rectangle(0, 0, img.Width, img.Height), Color.Teal, Color.Snow, 2f, true);
    53             ht.DrawString(check, font, jianbian, 0, 0);
    54             ht.DrawRectangle(new Pen(Color.Aqua), 0, 0, img.Width - 1, img.Height - 1);
    55             MemoryStream ms = new MemoryStream();
    56             img.Save(ms, ImageFormat.Jpeg);
    57             ht.Dispose();
    58             img.Dispose();
    59             return ms.ToArray();
    60         }
    61     }
    62 }
    createValidate.cs

    生成验证码的,可自己写。

    编写展现层

    首先需要在web.config中设置authentication节点为Forms验证模式,然后就可以在目录中任意设置访问级别了。

    <authentication mode="Forms">
      <forms loginUrl="~/manage/index.html" timeout="10080" defaultUrl="~/manage/Net/" />
    </authentication>

    登陆页面代码

     1 <!DOCTYPE html>
     2 <html xmlns="http://www.w3.org/1999/xhtml">
     3 <head>
     4     <meta charset="utf-8" />
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge,Chrome=1" />
     6     <meta http-equiv="X-UA-Compatible" content="IE=9" />
     7     <meta name="viewport" content="width=device-width, initial-scale=1">
     8     <title>汉之殇管理系统</title>
     9     <link href="css/bootstrap.css" rel="stylesheet" />
    10     <link href="css/admin.css" rel="stylesheet" />
    11     <!--[if lt IE 9]>
    12       <script src="http://apps.bdimg.com/libs/html5shiv/3.7/html5shiv.min.js"></script>
    13       <script src="http://apps.bdimg.com/libs/respond.js/1.4.2/respond.min.js"></script>
    14     <![endif]-->
    15 </head>
    16 <body class="login">
    17     <nav class="navbar navbar-default navbar-static-top">
    18         <div class="container">
    19             <div class="navbar-header">
    20                 <a href="login.html" class="navbar-brand">汉之殇管理系统</a>
    21             </div>
    22         </div>
    23     </nav>
    24     <div class="container">
    25         <div class="panel panel-default">
    26             <div class="panel-body">
    27                 <div id="ts"></div>
    28                 <h4 class="page-header">登陆</h4>
    29                 <div class="form-group has-feedback">
    30                     <label class="sr-only" for="userName">账号</label>
    31                     <input type="text" id="userName" class="form-control" placeholder="账号" maxlength="50" autofocus />
    32                     <span class="glyphicon glyphicon-user form-control-feedback" aria-hidden="true"></span>
    33                 </div>
    34                 <div class="form-group has-feedback">
    35                     <label class="sr-only" for="passWord">密码</label>
    36                     <input type="password" id="passWord" class="form-control" maxlength="50" placeholder="密码" />
    37                     <span class="glyphicon glyphicon-lock form-control-feedback" aria-hidden="true"></span>
    38                 </div>
    39                 <div class="form-group has-feedback">
    40                     <label class="sr-only" for="validateCode">验证码</label>
    41                     <input type="text" id="validateCode" class="form-control validateCode" placeholder="验证码" maxlength="4" />
    42                     <img src="checkLogin/ValidateCode.ashx" id="img" onclick="changeCode()" class="validateImg">
    43                     <a href="javascript:changeCode()">看不清,换一张</a>
    44                 </div>
    45                 <div class="form-group">
    46                     <input type="checkbox" id="remember" checked="checked" /> <span class="form-control-static">记住我 </span>
    47                     <button id="submit" type="button" class="btn btn-primary col-xs-offset-4" style="40%">登录</button>
    48                 </div>
    49             </div>
    50         </div>
    51     </div>
    52     <nav class="navbar navbar-default navbar-fixed-bottom">
    53         <div class="container">
    54             <div class="navbar-header">
    55                 <p class="navbar-text">&copy; 2015 汉之殇 版权所有</p>
    56             </div>
    57         </div>
    58     </nav>
    59     <script src="js/jquery-1.7.2.min.js"></script>
    60     <script src="js/status.js"></script>
    61     <script src="js/login.js"></script>
    62 </body>
    63 </html>
    index.html

    验证码

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Web;
     5 using CL;
     6 
     7 namespace UI.manage.checkLogin
     8 {
     9     /// <summary>
    10     /// ValidateCode 的摘要说明
    11     /// </summary>
    12     public class ValidateCode : IHttpHandler
    13     {
    14         public void ProcessRequest(HttpContext context)
    15         {
    16             context.Response.ContentType = "image/jpeg";
    17 
    18             var check = createVlidate.validation(4);
    19             byte[] buffer = createVlidate.drawImg(check);
    20 
    21             context.Response.BinaryWrite(buffer);
    22         }
    23 
    24         public bool IsReusable
    25         {
    26             get
    27             {
    28                 return false;
    29             }
    30         }
    31     }
    32 }
    ValidateCode.ashx

    登陆用的JS

     1 $(function () {
     2     $.get("checkLogin/Validate.ashx?rand=" + Math.random(0, 1), function (data) {
     3         if (data == "0") {
     4             location.href="/manage/Net/"
     5         }
     6     });
     7 
     8     if (top.location != self.location) {
     9         top.location = self.location;
    10     }
    11 
    12     var lj = window.location.toString();
    13     if (lj.lastIndexOf("?") != -1) {
    14         status("info", "请先登录!");
    15         $("#userName").focus();
    16     }
    17 
    18     $(".login").height(document.documentElement.clientHeight);
    19     document.onkeydown = function (e) {
    20         var ev = document.all ? window.event : e;
    21         if (ev.keyCode == 13) {
    22             $("#submit").click();
    23         }
    24     }
    25 });
    26 $("#submit").click(function () {
    27     //$("#submit").attr("disabled", "true");
    28     var userName = $("#userName").val();
    29     var passWord = $("#passWord").val();
    30     var validateCode = $("#validateCode").val();
    31     var remember = $("#remember:checked").val();
    32     if (userName != "") {
    33         if (passWord != "") {
    34             if (validateCode != "") {
    35                 if (validateCode.toLowerCase() == getCode()) {
    36                     $.post("checkLogin/Validate.ashx", { userName: userName, passWord: passWord, remember: remember }, function (data) {
    37                         changeCode();
    38                         if (data == "0") {
    39                             location.href = "Net/";
    40                         } else if (data == "1") {
    41                             status("no", "登陆失败,密码错误!");
    42                             $("#passWord").focus();
    43                             return false;
    44                         } else if (data == "2") {
    45                             status("no", "登陆失败,账号已被禁止登陆!");
    46                             $("#userName").focus();
    47                             return false;
    48                         } else {
    49                             status("no", "登陆失败,账号不存在!");
    50                             $("#userName").focus();
    51                             return false;
    52                         }
    53                     });
    54                     return false;
    55                 }
    56                 status("no", "验证码不正确!");
    57                 $("#validateCode").focus();
    58                 return false;
    59             }
    60             status("info", "请输入验证码!");
    61             $("#validateCode").focus();
    62             return false;
    63         }
    64         status("info", "请输入您的密码!");
    65         $("#passWord").focus();
    66         return false;
    67     }
    68     status("info", "请输入您的账号!");
    69     $("#userName").focus();
    70     return false;
    71 });
    72 function changeCode() {
    73     $("#img").attr("src", $("#img").attr("src") + "?");
    74 }
    75 function getCode() {
    76     var cookies = document.cookie.split(";");
    77     for (var i = 0; i < cookies.length; i++) {
    78         var validate = cookies[i].split("=");
    79         if (validate[0].replace(/(^s*)|(s*$)/g, "") == "check") {
    80             return validate[1].replace(/(^s*)|(s*$)/g, "");
    81         }
    82     }
    83 }
    login.js

    验证的一般处理程序

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Web;
     5 
     6 namespace UI.manage.checkLogin
     7 {
     8     /// <summary>
     9     /// Validate 的摘要说明
    10     /// </summary>
    11     public class Validate : IHttpHandler
    12     {
    13 
    14         public void ProcessRequest(HttpContext context)
    15         {
    16             var userName = context.Request["userName"];
    17             var passWord = context.Request["passWord"];
    18             var remember = context.Request["remember"] == null ? "" : context.Request["remember"];
    19             if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(passWord))
    20             {
    21                 var result = BLL.ManagerInfoBll.login(userName, passWord, remember);
    22                 context.Response.Write(result);
    23             }
    24             else
    25             {
    26                 if (context.Request.IsAuthenticated)
    27                 {
    28                     context.Response.Write("0");
    29                 }
    30             }
    31         }
    32 
    33         public bool IsReusable
    34         {
    35             get
    36             {
    37                 return false;
    38             }
    39         }
    40     }
    41 }
    Validate.ashx

    最后附上效果图如下:

    登陆后使用 Page.User.Identity.Name 获取用户标识。

    如下:

    获取信息及退出登陆如下:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Web;
     5 using System.Web.Security;
     6 using System.Web.UI;
     7 using System.Web.UI.WebControls;
     8 using BLL;
     9 using Model;
    10 
    11 namespace UI.manage.Net
    12 {
    13     public partial class _default : System.Web.UI.Page
    14     {
    15         protected void Page_Load(object sender, EventArgs e)
    16         {
    17             if (!IsPostBack)
    18             {
    19                 var userName = Page.User.Identity.Name;
    20                 int roleId = ManagerInfoBll.row(userName).mif_lever;
    21 
    22                 this.userId.InnerText = userName;
    23                 this.userRole.InnerText = ManagerInfoBll.getRole(roleId);
    24             }
    25 
    26             var logout = Request["logout"];
    27             if (!string.IsNullOrEmpty(logout))
    28             {
    29                 FormsAuthentication.SignOut();
    30                 Response.Redirect("../index.html");
    31             }
    32         }
    33     }
    34 }
    default.aspx.cs

    最后 在禁止匿名访问的目录下 新增一个web.config 内容如下

    <?xml version="1.0"?>
    <configuration>
      <system.web>
        <authorization>
          <deny users="?"/>
        </authorization>
      </system.web>
    </configuration>

    这样,当记住凭证后直接访问登陆或者该目录都可以直接跳转,如果点击退出或过期后,则自动跳出到登陆页面中。至此大功告成~

  • 相关阅读:
    Querying for Event Information
    通过注册表查询 .Net Framework 的版本
    [Batch脚本] if else 的格式
    逆天技能
    财运是靠自己争取的,而财商是可以通过后天学习提高的
    必须冒着可能付出惨痛代价的风险前进,否则你就只能永远做个井底之蛙
    财商低的六种表现
    中国大唐集团公司 主要经营范围
    中国大唐集团公司是2002年12月29日在原国家电力公司部分企事业单位基础上组建而成的特大型发电企业集团
    中国大唐集团公司在役及在建资产分布在全国31个省区市以及境外
  • 原文地址:https://www.cnblogs.com/baidawei/p/4785611.html
Copyright © 2011-2022 走看看