前面我们已经做好了一个文章管理功能模块,接下来,我们回头来做登录窗口,登录不仅涉及到登录验证还涉及到登录日志还有缓存时长等。

对于缓存的相关设置,我们已经写好封装在Bobo.Utilities.dll程序集中,我们只需要引用就好,没有的,请到此处下载

在实现之前,我们需要先在表现层创建一个Resource文件夹,用于存放我们公共的文件、图片及模板等,然后下载

IPScaner.zip,并加压到Resource文件夹下。

    QQwry.dat 纯真IP数据库收集了包括中国电信、中国网通、长城宽带、网通宽带、聚友宽带等 ISP 的最新准确 IP 地址数据。目前该库不是最新的数据,大家可以到网上下载到该目录下,这在我们做登录日志时可用到。

一、我们在区域BackstageModule下创建Login的控制器和视图:

(1)LoginController.cs控制器

using Bobo.Utilities;
using Bobo.Utilities.Membership;
using IA.Business.SystemBusiness;
using IA.Entity;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc; namespace IA.WebApp.Areas.BackstageModule.Controllers
{
/// <summary>
/// 后台登录控制器
/// </summary>
public class LoginController : Controller
{
//
// GET: /BackstageModule/Login/ public ActionResult Index()
{
return View();
}
/// <summary>
/// 登录
/// </summary>
/// <param name="Account"></param>
/// <param name="Password"></param>
/// <param name="Code"></param>
/// <returns></returns>
public ActionResult SubmitLogin(string Account, string Password, string Code)
{
try
{
Code = Md5Helper.CreateMd5(Code.ToLower(), 16);
if (Session["session_Userloginvcode"].ToString() != Code)
{
return Content(new JsonMessage { Success = false, Code = "-2", Message = "验证码不正确" }.ToString());
}
if (string.IsNullOrEmpty(Account) || string.IsNullOrEmpty(Password))
{
return Content(new JsonMessage { Success = false, Code = "-1", Message = "用户名或密码错误!" }.ToString());
}
IPScanerHelper objScan = new IPScanerHelper();
string IPAddress = NetHelper.LANIP;
objScan.IP = IPAddress;
objScan.DataPath = Server.MapPath("~/Resource/IPScaner/QQWry.Dat");
string IPAddressName = objScan.IPLocation(); int IsOk = new Base_UserBll().UserLogin(Account, Password, IPAddressName, IPAddress);
string strCode = "-1";
string Message = "";
string czMsg = "";
bool Success = false;
switch (IsOk)
{
case 1:
strCode = "1";
Message = "登录成功!";
czMsg = "登录成功!";
Success = true;
break;
case 2:
strCode = "-1";
Message = "登录失败,用户名或密码错误!";
czMsg = "密码错误!";
Success = false;
break;
case 3:
strCode = "-1";
Message = "登录失败,用户名或密码错误!";
czMsg = "账号不存在!";
Success = false;
break;
}
Base_SysLogBll.Instance.WriteLog(Account, OperationType.Login, strCode, czMsg + "、IP所在城市:" + IPAddressName);
return Content(new JsonMessage { Success = Success, Code = strCode, Message = Message }.ToString());
}
catch (Exception ex)
{
return Content(new JsonMessage { Success = false, Code = "-1", Message = "操作失败:" + ex.Message }.ToString());
} }
/// <summary>
/// 验证码
/// </summary>
/// <returns></returns>
public ActionResult VerifyCode()
{
int codeW = 80;
int codeH = 22;
int fontSize = 16;
string chkCode = string.Empty;
//颜色列表,用于验证码、噪线、噪点
Color[] color = { Color.Black, Color.Red, Color.Blue, Color.Green, Color.Orange, Color.Brown, Color.Brown, Color.DarkBlue };
//字体列表,用于验证码
string[] font = { "Times New Roman", "Verdana", "Arial", "Gungsuh", "Impact" };
//验证码的字符集,去掉了一些容易混淆的字符
char[] character = { '2', '3', '4', '5', '6', '8', '9', 'a', 'b', 'd', 'e', 'f', 'h', 'k', 'm', 'n', 'r', 'x', 'y', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W', 'X', 'Y' };
Random rnd = new Random();
//生成验证码字符串
for (int i = 0; i < 4; i++)
{
chkCode += character[rnd.Next(character.Length)];
}
//写入Session、验证码加密
Session["session_Userloginvcode"] = Md5Helper.MD5(chkCode.ToLower(), 16);
//创建画布
Bitmap bmp = new Bitmap(codeW, codeH);
Graphics g = Graphics.FromImage(bmp);
g.Clear(Color.White);
//画噪线
for (int i = 0; i < 1; i++)
{
int x1 = rnd.Next(codeW);
int y1 = rnd.Next(codeH);
int x2 = rnd.Next(codeW);
int y2 = rnd.Next(codeH);
Color clr = color[rnd.Next(color.Length)];
g.DrawLine(new Pen(clr), x1, y1, x2, y2);
}
//画验证码字符串
for (int i = 0; i < chkCode.Length; i++)
{
string fnt = font[rnd.Next(font.Length)];
Font ft = new Font(fnt, fontSize);
Color clr = color[rnd.Next(color.Length)];
g.DrawString(chkCode[i].ToString(), ft, new SolidBrush(clr), (float)i * 18 + 2, (float)0);
}
//将验证码图片写入内存流,并将其以 "image/Png" 格式输出
MemoryStream ms = new MemoryStream();
try
{
bmp.Save(ms, ImageFormat.Png);
return File(ms.ToArray(), @"image/Gif");
}
catch (Exception)
{
return null;
}
finally
{
g.Dispose();
bmp.Dispose();
}
} /// <summary>
/// 退出当前登录,清空所有用户cookie
/// </summary>
/// <returns></returns>
public ActionResult LoginOut()
{
/*****************************************
* 采用双cookie登录,则需要释放双cookie
* 标准cookie记录用户主要信息,附加cookie用于前台
* 附加cookie可记录自定义的任何信息
* ***************************************/
//清空当前登录用户信息
ManageProvider.Provider.EmptyCurrent();
ManageProvider.Provider.EmptyCurrent<Base_User>();
Session.Abandon(); //取消当前会话
Session.Clear(); //清除当前浏览器所以Session
return Content("1");
}
}
}

(2)Index视图

@{
ViewBag.Title = "登录"; }
<script src="~/Content/Scripts/jquery/jquery-1.8.2.min.js"></script>
<script src="~/Content/Scripts/jquery.form.js"></script>
<script src="~/Content/Scripts/boboui-jshelp.js"></script>
<script src="~/Content/Scripts/validator/boboui-validator.js"></script>
<script src="~/Content/Scripts/layer/layer.js"></script>
<script src="~/Content/Scripts/jQuery.md5.js"></script>
<link href="~/Content/Styles/base.css" rel="stylesheet" />
<link href="~/Content/Styles/main.css" rel="stylesheet" />
<body style="background-color: #4e95e5; " class="font-yahei">
<div class="mainBox">
<h1 style="text-align: center; font-weight: bold; font-size:24px; color: #fff; padding-bottom: 25px; letter-spacing: 2px;">枼落NO.1</h1>
<div class="Dialog-Box BoxS" style="margin: 0 auto; max-width: 500px; max-height: 300px; background-color: #fff; border-radius: 4px; padding: 0;">
<div class="Dialog-Tit-com" style="position:relative">系统用户登录</div>
<div class="login-Ico L"><img src="~/Content/Images/slice/users_03.png" width="78" height="76" /> </div>
<div class="login-box L">
<form id="form1" action="/BackstageModule/Login/SubmitLogin" method="post" enctype="multipart/form-data" style="margin: 1px">
<table class="layer-table-form">
<tr>
<td><span class="layer-form-tit">用户名:</span><input style="height:30px;border-radius:4px;" type="text" name="Account" class="layer-form-txt" id="Account" datacol="yes" err="用户名" checkexpession="NotNull" /></td>
</tr>
<tr>
<td><span class="layer-form-tit">密 &nbsp;&nbsp;码:</span><input style="height:30px;border-radius:4px;" type="password" name="Password" class="layer-form-txt" id="Password" datacol="yes" err="密码" checkexpession="NotNull" /></td>
</tr>
<tr>
<td>
<span class="layer-form-tit">验证码:</span><input type="text" name="Code" style="width: 100px; height: 30px; border-radius: 4px; " class="layer-form-txt" id="Code" datacol="yes" err="验证码" checkexpession="NotNull" />
<img id="codeImg" src="/BackstageModule/Login/VerifyCode" data-url="/BackstageModule/Login/VerifyCode" alt="点击切换验证码" onclick="switchCode($(this))" />
</td>
</tr>
</table>
</form>
</div>
<div class="Dialog-sub-com" style="position:relative">
<input type="button" value="登录" class="Dialog-btn subBtn" onclick="AcceptClick()">
<input type="button" value="取消" class="Dialog-btn extBtn" onclick="selfClose()">
</div>
</div>
</div>
<div class="clear" style="position:fixed;bottom:10px;color:#fff;text-align:center;width:100%;">页落素材网 Copyright 2008-2018 All Rights Reserved</div>
</body> <script type="text/javascript">
//提交表单
function AcceptClick() {
if (!CheckDataValid('#form1', true)) {
return false;
} var postData = GetWebControls("#form1");
postData.Password = escape($.md5(postData.Password));
$.post("/BackstageModule/Login/SubmitLogin?Code=" + $("#Code").val(), postData, function (data) {
layer.msg(data.Message, { icon: data.Code, time: 1000 }, function () {
if (data.Code > 0) {
selfClose();
location.href = "/BackstageModule/ArticleMange/Index";
}
else if (data.Code == -2) {
$("#Code").val("").focus();
switchCode($("#codeImg"));
}
});
}, "json");
}
//回车键
document.onkeydown = function (e) {
if (!e) e = window.event; //火狐中是 window.event
if ((e.keyCode || e.which) == 13) {
AcceptClick();
}
}
//自定义关闭窗口
function selfClose() {
var index = parent.layer.getFrameIndex(window.name);
parent.layer.close(index);
}
//切换验证码
function switchCode(obj) {
var url = obj.attr("data-url");
url += "?date=" + new Date().toString();
obj.attr("src", url);
}
</script>

二、在完成登录操作的过程后,我们需要对登录权限的认证,也就是非登录不可访问。

首先我们需要在表现层中的SystemExtension文件夹中添加LoginAuthorizeAttribute.cs和ManagerPermissionAttribute.cs登录权限类:

(1)LoginAuthorizeAttribute.cs

using Bobo.Utilities;
using Bobo.Utilities.Membership;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; namespace IA.WebApp.SystemExtension
{
/// <summary>
/// 登录权限认证
/// </summary>
public class LoginAuthorizeAttribute : AuthorizeAttribute
{
//地址参数的绝对路径("~/aaa/vvv")
private String _LoginUrl = String.Empty;
//无参构造器
public LoginAuthorizeAttribute() { } /// <summary>
/// 标记构造器,可传入登陆地址
/// </summary>
/// <param name="LoginUrl">地址参数的绝对路径("~/aaa/vvv")</param>
public LoginAuthorizeAttribute(string LoginUrl)
{
this._LoginUrl = LoginUrl;
}
/// <summary>
/// 响应前执行验证,查看当前用户是否有效
/// </summary>
/// <param name="filterContext"></param>
public override void OnAuthorization(AuthorizationContext filterContext)
{
var areaName = filterContext.RouteData.DataTokens["area"];
var controllerName = filterContext.RouteData.Values["controller"];
var action = filterContext.RouteData.Values["Action"];
var returnUrl = filterContext.RequestContext.HttpContext.Request.Url.ToString();
if (!StringHelper.IsNullOrEmpty(this._LoginUrl) && this._LoginUrl.IndexOf('?') == -1)
{
this._LoginUrl += ("?ReturnUrl=" + StringHelper.Escape(returnUrl));
}
if (this._LoginUrl.IndexOf("BackstageModule") != -1)
{
if (!ManageProvider.Provider.IsOverdue())
{
filterContext.Result = new RedirectResult(this._LoginUrl);
}
else
{
if (ManageProvider.Provider.Current().Code != "System")
{
filterContext.Result = new RedirectResult(this._LoginUrl);
}
}
}
else
{ //登录是否过期
if (!ManageProvider.Provider.IsOverdue())
{
filterContext.Result = new RedirectResult(this._LoginUrl);
}
else
{
if (ManageProvider.Provider.Current().Code == "System")
{
filterContext.Result = new RedirectResult(this._LoginUrl);
}
}
}
}
}
}

(2)ManagerPermissionAttribute.cs

using Bobo.Utilities;
using Bobo.Utilities.Membership;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; namespace IA.WebApp.SystemExtension
{
public class ManagerPermissionAttribute : AuthorizeAttribute
{
private PermissionMode _CustomMode;
/// <summary>默认构造</summary>
/// <param name="Mode">权限认证模式</param>
public ManagerPermissionAttribute(PermissionMode Mode)
{
_CustomMode = Mode;
}
/// <summary>权限认证</summary>
/// <param name="filterContext"></param>
public override void OnAuthorization(AuthorizationContext filterContext)
{
//登录权限认证
if (!ManageProvider.Provider.IsOverdue())
{
filterContext.Result = new RedirectResult("~/Login/Default");
}
//防止被搜索引擎爬虫、网页采集器
if (!this.PreventCreeper())
{
filterContext.Result = new RedirectResult("~/Login/Default");
}
//权限拦截是否忽略
if (_CustomMode == PermissionMode.Ignore)
{
return;
}
//执行权限认证
if (!this.ActionAuthorize(filterContext))
{
ContentResult Content = new ContentResult();
Content.Content = "<script type='text/javascript'>top.Loading(false);alert('很抱歉!您的权限不足,访问被拒绝!');</script>";
filterContext.Result = Content;
}
}
/// <summary>
/// 执行权限认证
/// </summary>
/// <returns></returns>
private bool ActionAuthorize(AuthorizationContext filterContext)
{
if (ManageProvider.Provider.Current().IsSystem && ManageProvider.Provider.Current().CompanyCategory != "SystemUnit")
return true;
var areaName = filterContext.RouteData.DataTokens["area"] + "/"; //获取当前区域
var controllerName = filterContext.RouteData.Values["controller"] + "/"; //获取控制器
var action = filterContext.RouteData.Values["Action"]; //获取当前Action
string requestPath = "/" + areaName + controllerName + action; //拼接构造完整url
string ModuleId = DESEncrypt.Decrypt(CookieHelper.GetCookie("ModuleId"));
//bool Result = Base_ModulePermissionBll.Instance.ActionAuthorize(requestPath.ToLower(), ManageProvider.Provider.Current().ObjectId, ModuleId, ManageProvider.Provider.Current().UserId);
return true;// Result;
}
/// <summary>
/// CA验证方法
/// </summary>
/// <param name="filterContext"></param>
/// <returns></returns>
private bool ActionCA(AuthorizationContext filterContext)
{
//TODO:如何在过滤器调用CA的前台检测方法返回值(NC)
if (ManageProvider.Provider.Current().IsSystem && ManageProvider.Provider.Current().CompanyCategory != "SystemUnit")
{
return true;
}
else
{
return true;
}
}
/// <summary>
/// 防止被搜索引擎爬虫、网页采集器
/// </summary>
/// <returns></returns>
private bool PreventCreeper()
{
return true;
}
}
}

权限认证做好后,我们在需要权限认证的控制器上加上[LoginAuthorize("~/BackstageModule/Login/Index")]这句了,例如文章控制器:

然后改造公共布局页_LayoutMange.cshtml:

@using Bobo.Utilities.Membership
@using IA.Business
<!DOCTYPE html>
<html>
@*后台公共模块*@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>@ViewBag.Title</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" media="screen" />
<link href="~/Content/Styles/main.css" rel="stylesheet" />
<link href="~/Content/Styles/base.css" rel="stylesheet" />
<script src="~/Content/Scripts/datepicker/WdatePicker.js"></script>
<script src="~/Content/Scripts/jquery/jquery-1.8.2.min.js"></script>
<script src="~/Content/Scripts/jquery.form.js"></script>
<script src="~/Content/Scripts/boboui-jshelp.js"></script>
<script src="~/Content/Scripts/validator/boboui-validator.js"></script>
<script src="~/Content/Scripts/layer/layer.js"></script>
<script src="~/Content/Scripts/Juicer/juicer.js"></script>
<script src="~/Content/Scripts/m_pager.js"></script>
</head>
<body class="set_body">
<div class="w_header font-yahei">
<div class="header-item">
<div class="mAuto">
<div class="L">页落素材网 - 用户管理后台 【当前用户】:@ManageProvider.Provider.Current().UserName</div>
<div class="R"><a href="javascript:;" id="LoginOut" style="color: #00b7f0;">【退出登录】</a></div>
</div>
</div>
<div class="header-nav clear">
<div class="mAuto">
<a href="/" class="logo L"> <img src="~/Content/Images/slice/logoMange.png" /></a>
<ul class="R nav-item">
<li class="L"><a href="/BackstageModule/Article/Index" class="wzgl">网站管理</a></li>
<li class="L"><a href="/BackstageModule/TrainSignupInfo/Index" class="hypx">区块链</a></li>
<li class="L"><a href="/BackstageModule/MemberManagement/Index" class="hygl">人工智能</a></li>
<li class="L"><a href="/">返回首页</a></li>
</ul>
</div>
</div>
</div> @RenderBody()
<div id="footer">
<div class="foot-tip w_footer">
<div class="webPage text-center">
页落素材网是网页特效下载社区,以提高效率、分享经验的理念,提供高品质实用、简单、易懂的Web页面特效。
</div>
</div>
</div> <script type="text/javascript">
$(function () {
$("#LoginOut").on("click", function () {
AjaxJson("/BackstageModule/Login/LoginOut", {}, function (data) {
layer.msg("您已退出登录,欢迎再来哦 ^_^", { icon: 6, shade: [0.3, '#000'] }, function () {
location.href = "/BackstageModule/Login/Index";
});
});
});
})
//复选框选定事件
function change(obj) {
var tr = obj.parentElement.parentElement;
if (obj.checked) {
tr.style.backgroundColor = '#e5eaff';
tr.style.borderColor = '#cacccb';
} else {
tr.style.backgroundColor = '#fff';
}
}
</script>
@RenderSection("scripts", required: false)
</body>
</html>

登录效果图预览

最新文章

  1. Mac Android开发环境变量的配置(java、sdk、ndk、gradle)
  2. NuGet 发布
  3. vs2012编译Qwt
  4. 远程办公《Remote》读书笔记:中国程序员在家上班月入过六万不是梦
  5. C/C++源代码到可执行程序的过程详解
  6. POJ 3692
  7. unity3d实现序列帧动画
  8. Qt之信号连接,你Out了吗?
  9. javascript Navigator对象
  10. makefile在编译的过程中出现“except class name”
  11. java-直接选择排序
  12. tomcat注册服务
  13. Python爬虫 爬取百合网的女人们和男人们
  14. C# 在窗体上可拖动控件
  15. google colab 使用指南
  16. 013 mysql中find_in_set()函数的使用
  17. 多线程开发之二 NSOperation
  18. numpy学习之矩阵之旅
  19. 在阿里云创建子域名,配置nginx,使用pm2部署node项目到ubuntu服务器
  20. 根据json对象的值替换json数组里的值

热门文章

  1. orm1.0
  2. Mac查看Python安装路径和版本
  3. python学习之旅1-2(基础知识)
  4. vue2-vux-fitness-project
  5. Codeforces 432C
  6. 64位linux源码安装mysql
  7. 【Leetcode链表】两两交换链表中的节点(24)
  8. 【vb.net机房收费系统】之sqlhelper 标签: 数据库 2015-05-17 10:47 819人阅读 评论(15)
  9. A - Archery Tournament 动态开点+vecotor 神仙题
  10. Linux中使用gcc编译文件