最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MVC使用極驗驗證制作登錄驗證碼學習筆記7

 更新時間:2016年09月21日 08:57:17   作者:叫我瑋仔  
這篇文章主要介紹了MVC使用極驗驗證制作登錄驗證碼學習筆記,具有一定的參考價值,感興趣的小伙伴們可以參考一下

       在之前的項目中,如果有需要使用驗證碼,基本都是自己用GDI+畫圖出來,簡單好用,但是卻也存在了一些小問題,首先若較少干擾線,則安全性不是很高,驗證碼容易被機器識別,若多畫太多干擾線條,機器人識別率下降的同時,人眼的識別率也同步下降(震驚哭)。更為重要的是,GDI+繪制的驗證碼一般來說也不會很美觀,如果做一個炫酷的登陸界面卻配了這樣一個驗證碼,畫風詭異,丑到極致。

      再后來瀏覽網(wǎng)頁的過程中,發(fā)現(xiàn)很多很多網(wǎng)站項目中都使用了一種叫極驗驗證的驗證碼,采用移動滑塊的方式進行驗證,方便美觀。而一番搜索之后了解到,官方提供的免費版也足以應付我手頭的大多數(shù)項目了,不禁想把在MVC學習過程中試著使用極驗驗證來作為登錄的驗證碼。

      極驗官方提供了C#的SDK和Demo供開發(fā)者參考,不過是Webform版本的,可讀性不是很高,而現(xiàn)在使用Webform進行網(wǎng)站開發(fā)的也基本消失了,我將在官方Webform代碼的基礎上,將其用在ASP.NET MVC程序中。

注冊極驗

到極驗官網(wǎng)注冊賬號之后進入后臺管理界面,點擊添加驗證

添加后我們可以得到ID和KEY

完成驗證邏輯

1. 首先我們需要引入官方的Geetestlib類

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.Net;
using System.IO;

namespace PMS.WebApp.Models
{
 /// <summary>
 /// GeetestLib 極驗驗證C# SDK基本庫
 /// </summary>
 public class GeetestLib
 {
  /// <summary>
  /// SDK版本號
  /// </summary>
  public const String version = "3.2.0";
  /// <summary>
  /// SDK開發(fā)語言
  /// </summary>
  public const String sdkLang = "csharp";
  /// <summary>
  /// 極驗驗證API URL
  /// </summary>
  protected const String apiUrl = "http://api.geetest.com";
  /// <summary>
  /// register url
  /// </summary>
  protected const String registerUrl = "/register.php";
  /// <summary>
  /// validate url
  /// </summary>
  protected const String validateUrl = "/validate.php";
  /// <summary>
  /// 極驗驗證API服務狀態(tài)Session Key
  /// </summary>
  public const String gtServerStatusSessionKey = "gt_server_status";
  /// <summary>
  /// 極驗驗證二次驗證表單數(shù)據(jù) Chllenge
  /// </summary>
  public const String fnGeetestChallenge = "geetest_challenge";
  /// <summary>
  /// 極驗驗證二次驗證表單數(shù)據(jù) Validate
  /// </summary>
  public const String fnGeetestValidate = "geetest_validate";
  /// <summary>
  /// 極驗驗證二次驗證表單數(shù)據(jù) Seccode
  /// </summary>
  public const String fnGeetestSeccode = "geetest_seccode";
  private String userID = "";
  private String responseStr = "";
  private String captchaID = "";
  private String privateKey = "";

  /// <summary>
  /// 驗證成功結果字符串
  /// </summary>
  public const int successResult = 1;
  /// <summary>
  /// 證結失敗驗果字符串
  /// </summary>
  public const int failResult = 0;
  /// <summary>
  /// 判定為機器人結果字符串
  /// </summary>
  public const String forbiddenResult = "forbidden";

  /// <summary>
  /// GeetestLib構造函數(shù)
  /// </summary>
  /// <param name="publicKey">極驗驗證公鑰</param>
  /// <param name="privateKey">極驗驗證私鑰</param>
  public GeetestLib(String publicKey, String privateKey)
  {
   this.privateKey = privateKey;
   this.captchaID = publicKey;
  }
  private int getRandomNum()
  {
   Random rand =new Random();
   int randRes = rand.Next(100);
   return randRes;
  }

  /// <summary>
  /// 驗證初始化預處理
  /// </summary>
  /// <returns>初始化結果</returns>
  public Byte preProcess()
  {
   if (this.captchaID == null)
   {
    Console.WriteLine("publicKey is null!");
   }
   else
   {
    String challenge = this.registerChallenge();
    if (challenge.Length == 32)
    {
     this.getSuccessPreProcessRes(challenge);
     return 1;
    }
    else
    {
     this.getFailPreProcessRes();
     Console.WriteLine("Server regist challenge failed!");
    }
   }

   return 0;

  }
  public Byte preProcess(String userID)
  {
   if (this.captchaID == null)
   {
    Console.WriteLine("publicKey is null!");
   }
   else
   {
    this.userID = userID;
    String challenge = this.registerChallenge();
    if (challenge.Length == 32)
    {
     this.getSuccessPreProcessRes(challenge);
     return 1;
    }
    else
    {
     this.getFailPreProcessRes();
     Console.WriteLine("Server regist challenge failed!");
    }
   }

   return 0;

  }
  public String getResponseStr()
  {
   return this.responseStr;
  }
  /// <summary>
  /// 預處理失敗后的返回格式串
  /// </summary>
  private void getFailPreProcessRes()
  {
   int rand1 = this.getRandomNum();
   int rand2 = this.getRandomNum();
   String md5Str1 = this.md5Encode(rand1 + "");
   String md5Str2 = this.md5Encode(rand2 + "");
   String challenge = md5Str1 + md5Str2.Substring(0, 2);
   this.responseStr = "{" + string.Format(
     "\"success\":{0},\"gt\":\"{1}\",\"challenge\":\"{2}\"", 0,
    this.captchaID, challenge) + "}";
  }
  /// <summary>
  /// 預處理成功后的標準串
  /// </summary>
  private void getSuccessPreProcessRes(String challenge)
  {
   challenge = this.md5Encode(challenge + this.privateKey);
   this.responseStr ="{" + string.Format(
    "\"success\":{0},\"gt\":\"{1}\",\"challenge\":\"{2}\"", 1, 
    this.captchaID, challenge) + "}";
  }
  /// <summary>
  /// failback模式的驗證方式
  /// </summary>
  /// <param name="challenge">failback模式下用于與validate一起解碼答案, 判斷驗證是否正確</param>
  /// <param name="validate">failback模式下用于與challenge一起解碼答案, 判斷驗證是否正確</param>
  /// <param name="seccode">failback模式下,其實是個沒用的參數(shù)</param>
  /// <returns>驗證結果</returns>
  public int failbackValidateRequest(String challenge, String validate, String seccode)
  {
   if (!this.requestIsLegal(challenge, validate, seccode)) return GeetestLib.failResult;
   String[] validateStr = validate.Split('_');
   String encodeAns = validateStr[0];
   String encodeFullBgImgIndex = validateStr[1];
   String encodeImgGrpIndex = validateStr[2];
   int decodeAns = this.decodeResponse(challenge, encodeAns);
   int decodeFullBgImgIndex = this.decodeResponse(challenge, encodeFullBgImgIndex);
   int decodeImgGrpIndex = this.decodeResponse(challenge, encodeImgGrpIndex);
   int validateResult = this.validateFailImage(decodeAns, decodeFullBgImgIndex, decodeImgGrpIndex);
   return validateResult;
  }
  private int validateFailImage(int ans, int full_bg_index, int img_grp_index)
  {
   const int thread = 3;
   String full_bg_name = this.md5Encode(full_bg_index + "").Substring(0, 10);
   String bg_name = md5Encode(img_grp_index + "").Substring(10, 10);
   String answer_decode = "";
   for (int i = 0;i < 9; i++)
   {
    if (i % 2 == 0) answer_decode += full_bg_name.ElementAt(i);
    else if (i % 2 == 1) answer_decode += bg_name.ElementAt(i);
   }
   String x_decode = answer_decode.Substring(4);
   int x_int = Convert.ToInt32(x_decode, 16);
   int result = x_int % 200;
   if (result < 40) result = 40;
   if (Math.Abs(ans - result) < thread) return GeetestLib.successResult;
   else return GeetestLib.failResult;
  }
  private Boolean requestIsLegal(String challenge, String validate, String seccode)
  {
   if (challenge.Equals(string.Empty) || validate.Equals(string.Empty) || seccode.Equals(string.Empty)) return false;
   return true;
  }

  /// <summary>
  /// 向gt-server進行二次驗證
  /// </summary>
  /// <param name="challenge">本次驗證會話的唯一標識</param>
  /// <param name="validate">拖動完成后server端返回的驗證結果標識字符串</param>
  /// <param name="seccode">驗證結果的校驗碼,如果gt-server返回的不與這個值相等則表明驗證失敗</param>
  /// <returns>二次驗證結果</returns>
  public int enhencedValidateRequest(String challenge, String validate, String seccode)
  {
   if (!this.requestIsLegal(challenge, validate, seccode)) return GeetestLib.failResult;
   if (validate.Length > 0 && checkResultByPrivate(challenge, validate))
   {
    String query = "seccode=" + seccode + "&sdk=csharp_" + GeetestLib.version;
    String response = "";
    try
    {
     response = postValidate(query);
    }
    catch (Exception e)
    {
     Console.WriteLine(e);
    }
    if (response.Equals(md5Encode(seccode)))
    {
     return GeetestLib.successResult;
    }
   }
   return GeetestLib.failResult;
  }
  public int enhencedValidateRequest(String challenge, String validate, String seccode, String userID)
  {
   if (!this.requestIsLegal(challenge, validate, seccode)) return GeetestLib.failResult;
   if (validate.Length > 0 && checkResultByPrivate(challenge, validate))
   {
    String query = "seccode=" + seccode + "&user_id=" + userID + "&sdk=csharp_" + GeetestLib.version;
    String response = "";
    try
    {
     response = postValidate(query);
    }
    catch (Exception e)
    {
     Console.WriteLine(e);
    }
    if (response.Equals(md5Encode(seccode)))
    {
     return GeetestLib.successResult;
    }
   }
   return GeetestLib.failResult;
  }
  private String readContentFromGet(String url)
  {
   try
   {
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
    request.Timeout = 20000;
    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
    Stream myResponseStream = response.GetResponseStream();
    StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));
    String retString = myStreamReader.ReadToEnd();
    myStreamReader.Close();
    myResponseStream.Close();
    return retString;
   }
   catch
   {
    return "";  
   }

  }
  private String registerChallenge()
  {
   String url = "";
   if (string.Empty.Equals(this.userID))
   {
    url = string.Format("{0}{1}?gt={2}", GeetestLib.apiUrl, GeetestLib.registerUrl, this.captchaID);
   }
   else
   {
    url = string.Format("{0}{1}?gt={2}&user_id={3}", GeetestLib.apiUrl, GeetestLib.registerUrl, this.captchaID, this.userID);
   }
   string retString = this.readContentFromGet(url);
   return retString;
  }
  private Boolean checkResultByPrivate(String origin, String validate)
  {
   String encodeStr = md5Encode(privateKey + "geetest" + origin);
   return validate.Equals(encodeStr);
  }
  private String postValidate(String data)
  {
   String url = string.Format("{0}{1}", GeetestLib.apiUrl, GeetestLib.validateUrl);
   HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
   request.Method = "POST";
   request.ContentType = "application/x-www-form-urlencoded";
   request.ContentLength = Encoding.UTF8.GetByteCount(data);
   // 發(fā)送數(shù)據(jù)
   Stream myRequestStream = request.GetRequestStream();
   byte[] requestBytes = System.Text.Encoding.ASCII.GetBytes(data);
   myRequestStream.Write(requestBytes, 0, requestBytes.Length);
   myRequestStream.Close();

   HttpWebResponse response = (HttpWebResponse)request.GetResponse();
   // 讀取返回信息
   Stream myResponseStream = response.GetResponseStream();
   StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));
   string retString = myStreamReader.ReadToEnd();
   myStreamReader.Close();
   myResponseStream.Close();

   return retString;

  }
  private int decodeRandBase(String challenge)
  {
   String baseStr = challenge.Substring(32, 2);
   List<int> tempList = new List<int>();
   for(int i = 0; i < baseStr.Length; i++)
   {
    int tempAscii = (int)baseStr[i];
    tempList.Add((tempAscii > 57) ? (tempAscii - 87)
     : (tempAscii - 48));
   }
   int result = tempList.ElementAt(0) * 36 + tempList.ElementAt(1);
   return result;
  }
  private int decodeResponse(String challenge, String str)
  {
   if (str.Length>100) return 0;
   int[] shuzi = new int[] { 1, 2, 5, 10, 50};
   String chongfu = "";
   Hashtable key = new Hashtable();
   int count = 0;
   for (int i=0;i<challenge.Length;i++)
   {
    String item = challenge.ElementAt(i) + "";
    if (chongfu.Contains(item)) continue;
    else
    {
     int value = shuzi[count % 5];
     chongfu += item;
     count++;
     key.Add(item, value);
    }
   }
   int res = 0;
   for (int i = 0; i < str.Length; i++) res += (int)key[str[i]+""];
   res = res - this.decodeRandBase(challenge);
   return res;
  }
  private String md5Encode(String plainText)
  {
   MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
   string t2 = BitConverter.ToString(md5.ComputeHash(UTF8Encoding.Default.GetBytes(plainText)));
   t2 = t2.Replace("-", "");
   t2 = t2.ToLower();
   return t2;
  }

 }
}

2. 獲取驗證碼

引入Jquery庫

<script src="~/Content/plugins/jquery/jquery-1.8.2.min.js"></script>

添加用于放置驗證碼的div(需要放到form表單中)

<div id="geetest-container">

</div>
添加JS代碼用于獲取驗證碼

<script>
 window.addEventListener('load', processGeeTest);

 function processGeeTest() {
  $.ajax({
   // 獲取id,challenge,success(是否啟用failback)
   url: "/Login/GeekTest",
   type: "get",
   dataType: "json", // 使用jsonp格式
   success: function (data) {
    // 使用initGeetest接口
    // 參數(shù)1:配置參數(shù),與創(chuàng)建Geetest實例時接受的參數(shù)一致
    // 參數(shù)2:回調(diào),回調(diào)的第一個參數(shù)驗證碼對象,之后可以使用它做appendTo之類的事件
    initGeetest({
     gt: data.gt,
     challenge: data.challenge,
     product: "float", // 產(chǎn)品形式
     offline: !data.success
    },
     handler);
   }
  });
 }

 var handler = function (captchaObj) {
  // 將驗證碼加到id為captcha的元素里
  captchaObj.appendTo("#geetest-container");

  captchaObj.onSuccess = function (e) {
   console.log(e);
  }

 };
</script>

processGeeTest方法中我們異步請求的地址“/Login/GeekTest”就是獲取驗證碼是后臺需要執(zhí)行的方法

public ActionResult GeekTest()
{
 return Content(GetCaptcha(),"application/json");
}

private string GetCaptcha()
{
 var geetest = new GeetestLib("3594e0d834df77cedc7351a02b5b06a4", "b961c8081ce88af7e32a3f45d00dff84");
 var gtServerStatus = geetest.preProcess();
 Session[GeetestLib.gtServerStatusSessionKey] = gtServerStatus;
 return geetest.getResponseStr();
}

3. 校驗驗證碼

注意,當提交form表單時,會將三個和極驗有關的參數(shù)傳到后臺方法(geetest_challenge、geetest_validate、geetest_seccode),若驗證碼未驗證成功,則參數(shù)為空值。

后臺驗證方法為:

private bool CheckGeeTestResult()
{
 var geetest = new GeetestLib("3594e0d834df77cedc7351a02b5b06a4", "b961c8081ce88af7e32a3f45d00dff84 ");
 var gtServerStatusCode = (byte)Session[GeetestLib.gtServerStatusSessionKey];
 var userId = (string)Session["userID"];

 var challenge = Request.Form.Get(GeetestLib.fnGeetestChallenge);
 var validate = Request.Form.Get(GeetestLib.fnGeetestValidate);
 var seccode = Request.Form.Get(GeetestLib.fnGeetestSeccode);
 var result = gtServerStatusCode == 1 ? geetest.enhencedValidateRequest(challenge, validate, seccode, userId) : geetest.failbackValidateRequest(challenge, validate, seccode);
 return result == 1;
}

我們可以在表單中判斷驗證碼是否成功校驗:

public ActionResult Login()
{
 if (!CheckGeeTestResult())
  return Content("no:請先完成驗證操作。");
 ....
}

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • asp.net實現(xiàn)數(shù)據(jù)從DataTable導入到Excel文件并創(chuàng)建表的方法

    asp.net實現(xiàn)數(shù)據(jù)從DataTable導入到Excel文件并創(chuàng)建表的方法

    這篇文章主要介紹了asp.net實現(xiàn)數(shù)據(jù)從DataTable導入到Excel文件并創(chuàng)建表的方法,涉及asp.net基于DataTable的數(shù)據(jù)庫及excel操作相關技巧,需要的朋友可以參考下
    2015-12-12
  • ASP.NET中Global和URLReWrite用法

    ASP.NET中Global和URLReWrite用法

    這篇文章主要介紹了ASP.NET中Global和URLReWrite用法,較為深入淺出的分析了Global.asax的功能及配置技巧,并實例分析了URLReWrite實現(xiàn)偽靜態(tài)的方法,需要的朋友可以參考下
    2015-06-06
  • asp.net截屏功能實現(xiàn)截取web頁面

    asp.net截屏功能實現(xiàn)截取web頁面

    這篇文章主要介紹了asp.net截屏功能實現(xiàn)截取web頁面,是非常實用的一個功能,需要的朋友可以參考下
    2014-08-08
  • ASP.NET GridView的Bootstrap分頁樣式

    ASP.NET GridView的Bootstrap分頁樣式

    這篇文章主要為大家詳細介紹了ASP.NET GridView的Bootstrap分頁樣式,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-11-11
  • ASP.NET常用小技巧

    ASP.NET常用小技巧

    這篇文章主要介紹了ASP.NET常用小技巧,非常實用,需要的朋友可以參考下
    2015-09-09
  • ASP.NET MVC實現(xiàn)批量文件上傳

    ASP.NET MVC實現(xiàn)批量文件上傳

    這篇文章主要為大家詳細介紹了ASP.NET MVC實現(xiàn)批量文件上傳,簡單介紹單文件上傳的實現(xiàn)方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-09-09
  • ASP.NET 導出到Excel時保留換行的代碼

    ASP.NET 導出到Excel時保留換行的代碼

    由于Excel畢竟不是 HTML,它有自己的樣式標準,在Excel 中,實現(xiàn)換行的方法是
    2008-12-12
  • 在?Net7.0?環(huán)境下如何使用?RestSharp?發(fā)送?Http(FromBody和FromForm)請求

    在?Net7.0?環(huán)境下如何使用?RestSharp?發(fā)送?Http(FromBody和FromForm)請求

    這篇文章主要介紹了在?Net7.0?環(huán)境下使用?RestSharp?發(fā)送?Http(FromBody和FromForm)請求,今天,我就兩個小的知識點,就是通過使用?RestSharp?訪問?WebAPI,提交?FromBody?和?FromForm?兩種方式的數(shù)據(jù),還是有些區(qū)別的,本文結合實例代碼介紹的非常詳細,需要的朋友參考下吧
    2023-09-09
  • ASP.NET中的參數(shù)與特殊類型和特性

    ASP.NET中的參數(shù)與特殊類型和特性

    這篇文章主要介紹了ASP.NET中的參數(shù)與特殊類型和特性,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2017-06-06
  • dotnet?命令行工具解決方案?PomeloCli詳解

    dotnet?命令行工具解決方案?PomeloCli詳解

    我們已經(jīng)有相當多的命令行工具實現(xiàn)或解析類庫,PomeloCli?并不是替代版本,它基于Nate?McMaster的杰出工作CommandLineUtils、DotNetCorePlugins實現(xiàn)了一整套的命令行開發(fā)、管理、維護方案,這篇文章主要介紹了dotnet命令行工具解決方案PomeloCli,需要的朋友可以參考下
    2024-05-05

最新評論

衡阳县| 本溪市| 哈尔滨市| 连城县| 抚松县| 阿坝县| 宁陵县| 霍城县| 蓬莱市| 图木舒克市| 平谷区| 平邑县| 徐水县| 丰宁| 犍为县| 洪洞县| 仙居县| 获嘉县| 虞城县| 长泰县| 九龙坡区| 图木舒克市| 金溪县| 钦州市| 淅川县| 嘉定区| 涞水县| 仲巴县| 乌兰县| 曲松县| 云龙县| 渭南市| 阿拉尔市| 洪雅县| 慈利县| 温州市| 辽源市| 贡觉县| 陆丰市| 丰宁| 南安市|