开发环境 :vue + asp.net core
验证码的实现过程
实现过程说明:
后台生成验证码,以图片的形式返回前端,但不传相应的生成验证码的字母及数字组合,
前台接收后台返回的FileConentResult型数据流文件,通过img接收,自动转化为图片展示在前台。
方法一:(个人未实现该方法)由于前后端分离,会存在跨域的问题,前台必须向后台传递cookie值或者一个唯一的id值,
才能保证后台以session形式获取对应值,即HttpContext.Session.SetString("ver",4位验证码)该方法不安全
方法二:故改为以下形式避免跨域问题,且安全
以token的形式进行登录人验证码的存储,登录成功后自动删除token验证码,仅保证在后端传输,不会明文出现在前台,避免暴力破解的可能。
具体实现如下:
1、首先,后台引用nuget包文件zkweb.system.drawing.4.0.1.nupkg
1.1如果是外网的开发环境,可直接搜索并引用nuget包文件。
1.2离线情况下,先到官网下载指定文件后,导入内网开发环境后,
步骤如下:
1、工具=》nuget包管理器=》程序包管理器设置=》程序包源=》如果nuget.org勾选,则取消勾选=》右上角加号=》名称:自定义M 源:选定官网下载的nupkg文件=>确定
2、工具=》nuget包管理器=》管理解决方案的nuget程序包=》浏览=》点击刚才定义名称M=>再点击右侧的安装,等待完成即可
2、后台生成几位验证码,几条干扰线,随机的字体颜色及随机的字体然后形成图片的长宽高(自定义)
[Route("CreateVer")]
[HttpGet]
public FileContentResult CreateVer()
{
int codeW = 80;
int codeH = 30;
int fontSize = 16;
Random rnd= new Random();
//颜色列表,用于验证码、噪线、噪点
Color[] color = { Color.Black, Color.Red, Color.Blue, Color.Green, Color.Orange, Color.Brown, Color.Brown, Color.DarkBlue };
//字体列表,用于验证码
string[] font = { "Times New Roman" };
//验证码的字符集,去掉了一些容易混淆的字符
//写入Session、验证码加密
//WebHelper.WriteSession("session_verifycode", 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 < 2; 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);
}//合法随机显示字符列表
string strLetters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
StringBuilder s = new StringBuilder();
//画验证码字符串
for (int i = 0; i < 4; i++)//4代表生成4位验证码
{
s.Append(strLetters.Substring(r.Next(0, strLetters.Length - 1), 1));
string fnt = font[rnd.Next(font.Length)];
Font ft= new Font(fnt, fontSize);
Color clr= color[rnd.Next(color.Length)];
g.DrawString(s[s.Length - 1].ToString(), ft, new SolidBrush(clr),(float)i * 18, (float)0);
}
//将验证码图片写入内存流,并将其以 "image/Png" 格式输出
MemoryStream ms = new MemoryStream();
try
{
bmp.Save(ms, ImageFormat.Png);
/*重点 此处存于后台自定义实体的token中,以便点击登录按钮时候进行验证*/
VerifyCodeService.Configure(s.toString());/*这个是token的启动配置,必须有*/
VerifyCode vermodel = new VerifyCode();
vermodel.loginSurever = s.toString();
var vertoken = jwtVerifyCodeHelper.IssueJwt(vermodel,_appSetting);//_appSetting为该登录机器的而唯一标识
return File(ms.ToArray(),@"image/Png");
}
catch (Exception)
{
return null;
}
finally
{
g.Dispose();
bmp.Dispose();
}
}
前台vue接收文件File
布局略
<el-form-item prop="ver">
<el-row :span = "24">
<el-col :span="12">
<el-input
v-model="form.loginver"
placeholder="请输入验证码"
hide-required-asterisk="false"
maxlength="6"
></el-input>
</el-col>
<el-col :span="12">
<img id="verimg" :src="imgcode" @click="refresh()">
</el-col>
</el-row>
</el-form-item>
布局略
data() {
return {
form: {
userCode: "",
password: "",
loginver:"",//输入验证码的值
},
imgcode:this.$api.getRoot() + '/api/Login/CreateVer' //请求后台获取验证码赋值给img
};
},
methods: {
refresh: function()//点击验证码刷新验证码
{
var num = Math.ceil(Math.random()*10);
this.imgcode = this.$api.getRoot() + '/api/Login/CreateVer?' + num;//防止缓存影响验证码的刷新
}
handleLogin: function(logincontinue) {//点击登录按钮时候的验证,如果验证码错误,自动再次向后端请求验证码,刷新前台验证码
_this.$api.post(url, param, response => {
if (response.code == 500) {
if (response.message.indexOf("验证码错误") > -1) {
_this.refresh();//刷新验证码
_this.form.loginver = "";//清空验证码的输入框
}
}
});
}
}