·您现在的位置: 云翼网络 >> 文章中心 >> 网站建设 >> 网站建设开发 >> ASP.NET网站开发 >> 分享一个html+js+ashx+easyui+ado.net权限管理系统

分享一个html+js+ashx+easyui+ado.net权限管理系统

作者:佚名      ASP.NET网站开发编辑:admin      更新时间:2022-07-23

分享一个html+js+ashx+easyui+ado.net权限管理系统

EasyUI、权限管理 这是个都快被搞烂了的组合,但是easyui的确好用,权限管理在项目中的确实用。一直以来博客园里也不少朋友分享过,但是感觉好的要不没源码,要不就是过度设计写的太复杂看不懂,也懒得去看懂,还有一些不是在推广自己的代码生成器就是在卖权限组件,看着漂亮的UI和完善的功能就是没源码学习,真是恼人。

前段时间公司项目阶段性结束了,就抽空把权限控制的部分抽取出来写了个html+js+ashx+ado.net的权限管理系统分享给一些初学者,这个权限系统demo没有MVC、没有ORM、数据库表都没设外键关系、级联删除等,所有需要级联操作的地方都是事务提交。界面上的所有操作基本都是jquery发Ajax请求ashx处理,ashx处理后输出json前台接收处理并配合easyui的组件响应给用户。基本没什么门槛,比较适合初学者。先看项目结构图:

项目结构基本就是模仿PetShop的,简单的7层,接口里定义方法,不同数据库不同实现,工厂负责创建访问数据库的对象,具体访问哪个数据库写在配置文件,都是老东西了也没什么说的。Model、BLL、SQLServerDAL等类库里的类都跟数据库表名保持一致,新建类库的时候修改了默认的命名空间(右键类库 - 属性 - 应用程序 - 程序集名称&默认命名空间),调用的时候用解决方案名.类库名.类名,这是我的个人习惯。具体查看源码

接下来简单分享下代码和贴图演示,懒的听我啰嗦的直接跳转到文章结尾下载源码。戳我

一、关于登陆

登陆就是用框架提供的FormsAuthentication类来做的,基本就是写cookie了,用户登录成功就加密下票证写到cookie里,简单的SetAuthCookie方法有点太简单了,只能写用户名到cookie里。我一般用FormsAuthenticationTicket类来做,可以把整个用户对象(userData)都写到cookie里。如果只把用户名写到cookie里,这样用户在别的浏览器登录然后执行修改密码操作,过来之前登陆过的浏览器,虽然改了密码,但还是可以继续保持登陆状态(博客园就是),这显然不符合常理。我的是把用户名和密码都保存到cookie里,然后用户每次访问都取出用户名和密码去数据库验证,如果找不到记录就干掉cookie。说到这肯定有人疑惑,把用户密码写到cookie里会不会不安全,用户密码本身就是不可逆的md5,写入cookie之前也再次进行了加密,我个人相信是比较安全的,且只有你自己看到cookie,如果担心有人抓包,可以把登陆功能部署到https上(个人想法,欢迎拍砖)。

简单来说,我的登陆逻辑:用户访问登陆页面就ajax请求后台验证cookie,只有用户名和密码匹配上(用户没修改密码)、状态IsAble可用(管理员没在后台禁用此用户)等等的情况下直接跳到首页,其他都干掉cookie。这样做的好处就是管理员可以很方便的控制一个用户的状态,就算他保存了cookie,因为服务端每次都有验证IsAble字段,管理员也可以很方便的禁用这个用户。还有不影响登陆的情况:比如用户修改了自己的姓名等情况也得重写cookie,否则从cookie里取出来的用户名显示到欢迎区域就不准确了,这里用FormsAuthenticationTicket就完美了,userData参数可以存很多东西。

首次访问登陆页面判断是否登陆和用户点击登陆按钮的示例代码:

case "iflogin":    //System.Threading.Thread.Sleep(5000);    if (context.Request.IsAuthenticated)    {        FormsIdentity id = (FormsIdentity)context.User.Identity;        FormsAuthenticationTicket tickets = id.Ticket;        //获取票证里序列化的用户对象(反序列化)        ZGZY.Model.User userCheck = new javaScriptSerializer().Deserialize<ZGZY.Model.User>(tickets.UserData);        //执行登录操作        ZGZY.Model.User userReLogin = new ZGZY.BLL.User().UserLogin(userCheck.UserId, userCheck.UserPwd);        if (userReLogin == null)        {            FormsAuthentication.SignOut();            context.Response.Write("{\"msg\":\"用户名或密码错误!\",\"success\":false}");        }        else if (!userReLogin.IsAble)        {            FormsAuthentication.SignOut();            context.Response.Write("{\"msg\":\"用户已被禁用!\",\"success\":false}");        }        else        {            //记录登录日志            ZGZY.Model.LoginLog loginInfo = new Model.LoginLog();            loginInfo.UserIp = context.Request.UserHostAddress;            loginInfo.City = context.Request.Params["city"] ?? "未知";   //访问者所处城市            loginInfo.UserName = context.User.Identity.Name;            loginInfo.Success = true;            new ZGZY.BLL.LoginLog().WriteLoginLog(loginInfo);            context.Response.Write("{\"msg\":\"已登录过,正在跳转!\",\"success\":true}");        }    }    else        context.Response.Write("{\"msg\":\"nocookie\",\"success\":false}");    break;case "login":    //System.Threading.Thread.Sleep(5000);    string userIp = context.Request.UserHostAddress;    string city = context.Request.Params["city"] ?? "未知";    string remember = context.Request.Params["remember"] ?? "";   //记住密码天数    string name = context.Request.Params["loginName"];    string pwd = ZGZY.Common.Md5.GetMD5String(context.Request.Params["loginPwd"]);  //md5加密    DateTime? lastLoginTime;    if (new ZGZY.BLL.LoginLog().CheckLogin(userIp, out lastLoginTime) != null)    {        DateTime dtNextLogin = Convert.ToDateTime(lastLoginTime);        context.Response.Write("{\"msg\":\"密码错误次数达到5次,请在" + dtNextLogin.AddMinutes(30).ToShortTimeString() + "之后再登陆!\",\"success\":false}");    }    else    {        ZGZY.Model.LoginLog loginInfo = new Model.LoginLog();        loginInfo.UserName = name;        loginInfo.UserIp = userIp;        loginInfo.City = city;        ZGZY.Model.User currentUser = new ZGZY.BLL.User().UserLogin(name, pwd);        if (currentUser == null)        {            context.Response.Write("{\"msg\":\"用户名或密码错误!\",\"success\":false}");            loginInfo.Success = false;            new ZGZY.BLL.LoginLog().WriteLoginLog(loginInfo);        }        else if (currentUser.IsAble == false)        {            context.Response.Write("{\"msg\":\"用户已被禁用!\",\"success\":false}");            loginInfo.Success = false;            new ZGZY.BLL.LoginLog().WriteLoginLog(loginInfo);        }        else        {            //记录登录日志            loginInfo.Success = true;            new ZGZY.BLL.LoginLog().WriteLoginLog(loginInfo);            context.Response.Write("{\"msg\":\"登录成功!\",\"success\":true}");            DateTime dateCookieExpires;  //cookie有效期            switch (remember)            {                case "notremember":                    dateCookieExpires = new DateTime(9999, 12, 31);   //默认时间                    break;                case "oneday":                    dateCookieExpires = DateTime.Now.AddDays(1);                    break;                case "sevenday":                    dateCookieExpires = DateTime.Now.AddDays(7);                    break;                case "onemouth":                    dateCookieExpires = DateTime.Now.AddDays(30);                    break;                case "oneyear":                    dateCookieExpires = DateTime.Now.AddDays(365);                    break;                default:                    dateCookieExpires = new DateTime(9999, 12, 31);                    break;            }            FormsAuthenticationTicket ticket = new FormsAuthenticationTicket            (                2,                currentUser.UserId,                DateTime.Now,                dateCookieExpires,                false,                new JavascriptSerializer().Serialize(currentUser)  //序列化当前用户对象            );            string encTicket = FormsAuthentication.Encrypt(ticket);            HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);            if (dateCookieExpires != new DateTime(9999, 12, 31))    //不是默认时间才设置过期时间,否则会话cookie                cookie.Expires = dateCookieExpires;            context.Response.Cookies.Add(cookie);        }    }    break;

博客园的做法是访问登陆页面就把cookie干掉(如果有),我个人还是觉得有cookie再访问登陆页面就跳转到首页比较好。你可以访问博客园的登陆页面试试(慎点,会干掉你的cookie)

另外登陆功能还调用了sina的api获取用户登录城市、同一个ip连续5次输错密码就30分钟之内不让登陆,详细请自己查看源码。

二、权限控制

权限控制基本就是用户拥有角色(可以多角色)、角色拥有菜单不同按钮的权限(浏览、增加、修改、删除等)。这样基本做到了单用户多角色,界面上的操作按钮根据用户拥有的权限显示或者不显示。先添加一个用户,默认密码123:

"已经改密"如果不勾选上,那么下次这个用户登录就会弹框让他修改密码(这个功能是跟添加用户默认密码是123相互呼应的)。直接用添加的用户登录会什么都没有,因为此用户没有任何菜单权限:

左侧的目录树是EasyUI的Tree组件,打开页面的时候ajax取出当前用户拥有的菜单权限然后展示出来,不同用户看到的菜单是不一样的。后台操作基本就是一个连表查询,DataTable取出来然后遍历构建这个Tree:

/// <summary>/// 根据用户主键id查询用户可以访问的菜单/// </summary>public DataTable GetUserMenu(int id){    StringBuilder strSql = new StringBuilder();    strSql.Append("select distinct(m.Name) menuname,m.Id menuid,m.Icon icon,u.Id userid,u.UserId username,m.ParentId menuparentid,m.Sort menusort,m.LinkAddress linkaddress from tbUser u");    strSql.Append(" join tbUserRole ur on u.Id=ur.UserId");    strSql.Append(" join tbRoleMenuButton rmb on ur.RoleId=rmb.RoleId");    strSql.Append(" join tbMenu m on rmb.MenuId=m.Id");    strSql.Append(" where u.Id=@Id order by m.ParentId,m.Sort");    return ZGZY.Common.SqlHelper.GetDataTable(ZGZY.Common.SqlHelper.connStr, CommandType.Text, strSql.ToString(), new SqlParameter("@Id", id));}

重新登陆下管理员账户添加一个浏览角色:

给角色授权:

  • 上一篇文章:
  • 下一篇文章: