首先背景是exchange的邮箱系统没有后台源代码。因为这个原因,生成验证码的机制放在aspx的runat="sever"后台代码里面。

首先需要找到iis中logon.aspx文件。在这里找到输入邮箱名和密码的input元素,对应增加上输入验证码的input和显示验证码图片的img元素。

需要增加两个文件:VerifyCode.aspx是用户输入进行输入的验证码验证操作的代码;GetImg.aspx是用于显示验证码图片的,即将之前添加的img的src设置为这个GetImg.aspx即可。至于点击img之后自动刷新,则属于体验性的改进。

代码具体执行逻辑是GetImg在load的时候,将随机生成的验证码加密之后,存在客户端浏览器的cookie中,同时创建一个Img对象,将4位验证码字符按顺序输出到img对象上,同时img随机分布一些点pixel,之后图片的stream返回到浏览器上。

而VerifyCode的验证则是则根据输入的内容和之前的cookie存的密文解密之后进行比较,如果一致,则通过验证。

VerifyCode.aspx代码如下:

<%@ Page Language="C#" AutoEventWireup="true" Debug="true" %>

<%@ Import Namespace="System.Security.Cryptography" %>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
if (Request.Cookies["yzmCode"] != null && Request.QueryString["yzmc"] != null)
{
string code = Decrypt(Request.Cookies["yzmCode"].Value).ToUpper();
//Response.Write("code"+code+"\n");
//Response.Write("code"+code+"\n");
//Response.End();
string ucode = Request.QueryString["yzmc"].ToUpper();
if (code == ucode)
{
Response.Write("ok");
Response.End();
}
else
{
Response.Write("error");
Response.End();
}
}
else
{
Response.Write("error2");
Response.End();
}
}
public static string Decrypt(string Text)
{
string sKey = "Exchange";
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
int len;
len = Text.Length / ;
byte[] inputByteArray = new byte[len];
int x, i;
for (x = ; x < len; x++)
{
i = Convert.ToInt32(Text.Substring(x * , ), );
inputByteArray[x] = (byte)i;
}
des.Key = ASCIIEncoding.ASCII.GetBytes(System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sKey, "md5").Substring(, ));
des.IV = ASCIIEncoding.ASCII.GetBytes(System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sKey, "md5").Substring(, ));
System.IO.MemoryStream ms = new System.IO.MemoryStream();
CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
cs.Write(inputByteArray, , inputByteArray.Length);
cs.FlushFinalBlock();
return Encoding.Default.GetString(ms.ToArray());
}
</script>

GetImg.aspx代码如下:

<%@ Page Language="C#" AutoEventWireup="true" %>

<%@ Import Namespace="System.Drawing" %>
<%@ Import Namespace="System.Drawing.Imaging" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Security.Cryptography" %>
<script runat="server">
public static string Encrypt(string Text)
{
string sKey = "Exchange";
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
byte[] inputByteArray;
inputByteArray = Encoding.Default.GetBytes(Text);
des.Key = ASCIIEncoding.ASCII.GetBytes(System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sKey, "md5").Substring(, ));
des.IV = ASCIIEncoding.ASCII.GetBytes(System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sKey, "md5").Substring(, ));
System.IO.MemoryStream ms = new System.IO.MemoryStream();
CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(inputByteArray, , inputByteArray.Length);
cs.FlushFinalBlock();
StringBuilder ret = new StringBuilder();
foreach (byte b in ms.ToArray())
{
ret.AppendFormat("{0:X2}", b);
}
return ret.ToString();
}
public static string Decrypt(string Text)
{
string sKey = "Exchange";
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
int len;
len = Text.Length / ;
byte[] inputByteArray = new byte[len];
int x, i;
for (x = ; x < len; x++)
{
i = Convert.ToInt32(Text.Substring(x * , ), );
inputByteArray[x] = (byte)i;
}
des.Key = ASCIIEncoding.ASCII.GetBytes(System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sKey, "md5").Substring(, ));
des.IV = ASCIIEncoding.ASCII.GetBytes(System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sKey, "md5").Substring(, ));
System.IO.MemoryStream ms = new System.IO.MemoryStream();
CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
cs.Write(inputByteArray, , inputByteArray.Length);
cs.FlushFinalBlock();
return Encoding.Default.GetString(ms.ToArray());
}
protected void Page_Load(object sender, EventArgs e)
{
int codeW = ;
int codeH = ;
int fontSize = ;
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 = { '', '', '', '', '', '', '', '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 = ; i < ; i++)
{
chkCode += character[rnd.Next(character.Length)];
}
//Session["yzmCode"] = chkCode;
HttpCookie cook = new HttpCookie("yzmCode", Encrypt(chkCode));
cook.Expires = DateTime.Now.AddMinutes();
Response.Cookies.Add(cook);
Bitmap bmp = new Bitmap(codeW, codeH);
Graphics g = Graphics.FromImage(bmp);
g.Clear(Color.White);
for (int i = ; i < ; 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 = ; 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 * + , (float));
}
for (int i = ; i < ; i++)
{
int x = rnd.Next(bmp.Width);
int y = rnd.Next(bmp.Height);
Color clr = color[rnd.Next(color.Length)];
bmp.SetPixel(x, y, clr);
}
Response.Buffer = true;
Response.ExpiresAbsolute = System.DateTime.Now.AddMilliseconds();
Response.Expires = ;
Response.CacheControl = "no-cache";
Response.AppendHeader("Pragma", "No-Cache");
MemoryStream ms = new MemoryStream();
try
{
bmp.Save(ms, ImageFormat.Png);
Response.ClearContent();
Response.ContentType = "image/Png";
Response.BinaryWrite(ms.ToArray());
}
finally
{
bmp.Dispose();
g.Dispose();
}
}
</script>

注意:加密解密对应的sKey变量要一致。

判断验证码是否输入正确的js逻辑(简单点描述就是发起get请求,地址是上面提到的VerifyCode.aspx,参数和代码中对应上即可):

var codeVaule = $("#yzm").val();
if(codeVaule == ""){
$("#yzm-tip").html("验证码不能为空");
return false;
}else if(codeVaule.length!=4){
$("#yzm-tip").html("验证码位数不正确");
return false;
}else{
$.get("VerifyCode.aspx?yzmc="+codeVaule,{},function(data){
if(data=="ok"){
$("#yzm-tip").html("验证码正确");
//$(".btnSignin").click();
clkLgn();//登录逻辑
bo=true;
}else{
$("#yzm-tip").html("验证码错误!");
}
});
}
return bo;

(为了简单,使用了jquery,引用即可)

触发登录操作的js函数是clkLgn(),这个放在flogon.js这个脚本文件里面,由于存在点击登录按钮和直接回车(e.keyCode == 13)直接执行登录的两种场景,因此此处需要看清js代码。具体倒没什么难度。

可以修改clkLgn()的代码逻辑,直接在里面增加对输入验证码进行验证的逻辑,然后确定是否走真正的登录的代码。也可以在点击登录按钮或者回车的两处逻辑上分别走验证请求再处理。

本身加上验证码的目的只是为了防止密码撞库,快速达到要求即可。

点击验证码图片自动刷新的改进:

    function refreshImg(){
$("#yzmImg")[0].src="GetImg.aspx?"+Math.random();
}

exchange邮箱系统增加验证码机制的更多相关文章

  1. web系统登陆页面增加验证码

    传统登陆页面中包含两个输入项: • 用户名 • 密码有时为了防止机器人进行自动登陆操作,或者防止恶意用户进行用户信息扫描,需增加动态验证码功能.此时,登陆页面中包含了三个输入项: • 用户名 • 密码 ...

  2. Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6642463 在前面几篇文章中,我们详细介绍了A ...

  3. [转帖]实时流处理系统反压机制(BackPressure)综述

    实时流处理系统反压机制(BackPressure)综述 https://blog.csdn.net/qq_21125183/article/details/80708142 2018-06-15 19 ...

  4. TODO:Laravel增加验证码

    TODO:Laravel增加验证码1. 先聊聊验证码是什么,有什么作用?验证码(CAPTCHA)是"Completely Automated Public Turing test to te ...

  5. (3)MEF插件系统中通信机制的设计和实现

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 一般的WinForm中通过C#自带的Event机制便能很好的实 ...

  6. yii2增加验证码详细步骤

    作者:白狼 出处:http://www.manks.top/article/yii2_captcha本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留 ...

  7. (原创)AD账户误删导致Exchange邮箱被删 莫苦恼

    由于人员变动,离职人员AD账户和邮箱经常要删除.但是在删除AD账户的时候难免会犯错,将在用的用户给删除了,这是个痛苦的事情, 然后你会发现Exchange邮箱也会跟着删除,抓狂了..,还好,幸亏这里进 ...

  8. sharepoint获取exchange邮箱报错:该帐户无权模拟所请求的用户

    现象: sharepoint获取exchange邮箱报错:该帐户无权模拟所请求的用户 处理办法: 1.Open the Exchange Management Shell 2.输入: New-Mana ...

  9. cas sso单点登录系列5_cas单点登录增加验证码功能完整步骤

    转:http://blog.csdn.net/ae6623/article/details/8919718 本篇教程cas-server端下载地址:解压后,直接放到tomcat的webapp目录下就能 ...

随机推荐

  1. WebApi-如何实现接口加密

    方法一 加一个访问token.例如你的api地址是http://www.example.com/api.php需要接受的参数有a,b,c三个那么可以加一个验证token(通过约定的key加密生成). ...

  2. 谋哥:《App自推广》开篇之回到远古人类

    [谋哥每天一干货.第六十八篇] 这两天帮谋天团的杨整体验他的App--"闪聊"的内測新版,改版后这款App命名为"美丫",一款致力于打造国内首款专注于女性社交的 ...

  3. iOS 7 导航栏颜色设定与适配

    iOS7 设置navigationBar的颜色,新增了一个属性 barTintColor CGFloat osVersion = [[UIDevice currentDevice].systemVer ...

  4. 算法笔记_148:有向图欧拉回路求解(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 Description A catenym is a pair of words separated by a period such that t ...

  5. 算法笔记_016:凸包问题(Java)

    目录 1 问题描述 2 解决方案 2.1 蛮力法 1 问题描述 给定一个平面上n个点的集合,它的凸包就是包含所有这些点的最小凸多边形,求取满足此条件的所有点. 另外,形象生动的描述: (1)我们可以把 ...

  6. JUnit单元测试基础要点

    JUnit单元测试基础要点 1.JUnit是一种测试代码的框架,测试的目的是:保证代码没错,而不是保证代码正确. 2.测试类一般不要和目标类放在一起,但编译成的class文件是放在一起的. 3.单元测 ...

  7. taro 填坑之路(一)taro 项目回顾

    (1)像素写法 PX -- 大写,否则会自动成rem (2)拿取列表第一条数据 let { activity:[firstItem] } = this.state; (3)使用props 需要设置默认 ...

  8. 【Oracle】新建用户,删除用户,授权

    一.创建用户 oracle内部有两个建好的用户:system和sys.用户可直接登录到system用户以创建其他用户,因为system具有创建别 的用户的 权限. 在安装oracle时,用户或系统管理 ...

  9. javascript 的继承实例

    shape.prototype = { getEdge:function(){ return this.edge; }, getArea:function(){ return this.a*this. ...

  10. [Asp.net]Calendar+JqueryUi实现日程管理——添加日程

    引言 之前在博客园里看到一篇文章,介绍的云日程,所以就一直在想如果是自己该如何实现,所以就自己尝试弄了一个简单的demo. 项目 效果图 日历控件,本来想弄一个js版的,后来考虑,js版的会花费更多的 ...