驗證碼 Captcha 之大插件


驗證碼 Captcha 之大插件小用

不知何年何月才能完成OADemo啊,總之還是一步一步來吧,這段時間開始着手了,先做登陸。  前段時間研究了一下在CentOS7下安裝Mysql和Memcached服務,並測試了用C#操作,結果還行。

   今天做一個簡單的基於Bootstarp的響應式登陸頁面(其實是在網上下的模板),不管是登陸還是注冊吧,都會用到驗證碼,以前是用GDI繪出來的,覺得太丑了,百度的關於.net的驗證碼絕大多數也是用的這種方法,最后試了一下captcha,覺得還挺好看的,所以就試着用用。

  nugit控制台install-package captcha到項目就行了,下載好了有個readme.txt文件,照着搞了一下,挺方便的

 

后台代碼這樣寫的

復制代碼
[HttpPost]
        [CaptchaValidation("CaCode", "ExampleCaptcha", "Incorrect CAPTCHA code!")]
        public ActionResult ExampleAction(bool captchaValid)
        {
            
            if (!captchaValid)
            {
                return Content("no");
            }
            else
            {
                return Content("ok");
            }
        }
復制代碼

前台這樣子的

復制代碼
<form action="/Example/ExampleAction" method="post">
        @{
            MvcCaptcha exampleCaptcha = new MvcCaptcha("ExampleCaptcha");
            exampleCaptcha.UserInputID = "CaCode";
            exampleCaptcha.ImageStyle = BotDetect.ImageStyle.CaughtInTheNet2;
            @Html.Captcha(exampleCaptcha)
            @*@Html.TextBox("CaCode")*@
            <input type="text" id="CaCode" name="CaCode"/>
                   }
            <input type="submit"  value="GO" />
        </form>
復制代碼

這都是照着readme搞的,當然還有注冊路由的

復制代碼
public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.IgnoreRoute("{*botdetect}", new { botdetect = @"(.*)BotDetectCaptcha\.ashx" });
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
復制代碼

 

就這三步就行了,然后測試一下,先輸個錯的試試,點GO,輸出no,很好,再搞個對的,輸出ok相當可以,再然后,不小心輸錯了還是ok,再然后空的還是ok???

把瀏覽器關了,重新生成再打開試,哪怕第一次是錯的也是輸出ok。另外還有一個問題點圖片就會轉到https://captcha.org/captcha.html?asp.net這個地址。

問題一

出現這個問題按理說應該是好事,說明插件幫我們做了緩存驗證碼的事,並且還設置了過期時間,將部分屬性打印到頁面看看情況

復制代碼
<form action="/Example/ExampleAction" method="post">
        @{
            MvcCaptcha exampleCaptcha = new MvcCaptcha("ExampleCaptcha");
            exampleCaptcha.UserInputID = "CaCode";
            exampleCaptcha.ImageStyle = BotDetect.ImageStyle.CaughtInTheNet2;
            @Html.Captcha(exampleCaptcha)
            @*@Html.TextBox("CaCode")*@
            <input type="text" id="CaCode" name="CaCode"/>
            <ul>
                <li>HelpLinkUrl:  @exampleCaptcha.HelpLinkUrl</li>
                <li>AddInitScript: @exampleCaptcha.AddInitScript</li>
                <li>AdditionalCssClasses: @exampleCaptcha.AdditionalCssClasses</li>
                <li>AdditionalInlineCss: @exampleCaptcha.AdditionalInlineCss</li>
                <li>AddScriptInclude: @exampleCaptcha.AddScriptInclude</li>
                <li>AutoClearInput: @exampleCaptcha.AutoClearInput</li>
                <li>AutoFocusInput: @exampleCaptcha.AutoFocusInput</li>
                <li>AutoReloadTimeout: @exampleCaptcha.AutoReloadTimeout</li>
                <li>CodeLength: @exampleCaptcha.CodeLength</li>
                <li>CodeStyle: @exampleCaptcha.CodeStyle</li>
                <li>CodeTimeout: @exampleCaptcha.CodeTimeout</li>
                <li>HelpLinkEnabled: @exampleCaptcha.HelpLinkEnabled</li>
                <li>HelpLinkText: @exampleCaptcha.HelpLinkText</li>
                <li>IconsDivWidth: @exampleCaptcha.IconsDivWidth</li>
                <li>ReloadIconUrl: @exampleCaptcha.ReloadIconUrl</li>
                <li>SoundIconUrl: @exampleCaptcha.SoundIconUrl</li>
                <li>ImageStyle: @exampleCaptcha.ImageStyle</li>
                <li>Locale: @exampleCaptcha.Locale</li>
                <li> @exampleCaptcha.HelpLinkMode</li>                
                <li> @exampleCaptcha.WebCaptcha.CaptchaImageUrl</li>
                <li> @exampleCaptcha.WebCaptcha.CaptchaBase.GetCode("ExampleCaptcha", BotDetect.CodeGenerationPurpose.ImageGeneration).CaptchaCode</li>
            </ul>
        }
            <input type="submit"  value="GO" />
        </form>
復制代碼

 

 

 

從第一個屬性來看應該是解決問題二的辦法,但是很不幸,設置exampleCaptcha.HelpLinkUrl和HelpLinkText的值無效,結果還是回到了默認值。

還有就是CodeTimeout也是設置無效。在webconfig中

<sessionState mode="InProc" cookieless="AutoDetect" timeout="20" sessionIDManagerType="BotDetect.Web.CustomSessionIdManager, BotDetect" />

設置timeout小於20的值也無效,可能是有個最小值限定吧,這里我還沒有試過超過20的值,暈!

其它的還好吧。

最后一個屬性是我企圖找出當前的驗證碼,依然很不幸,並不是,到現在我還沒辦法得到。之所以想得當驗證碼,其一是我覺得它幫我做的就是在session中緩存了驗證碼,可我並不想用session,如果只是保存在cookie中,那敢情好,我也無需得到驗證碼。

看看點擊刷新按鈕的請求

可以看出有三個GET請求,前兩個是請求刷新和聲音的按鈕,后面一個是請求圖片的。主要看后面一個,看來是有請求cookie的,並且有兩個key。雖然如此,可我還並不肯定到底有沒有用session緩存,關於這個,希望路過的大牛給予指導

再看看參數,有四個參數,每次請求只有d的值是變化的,這就是跟我們以前用的驗證碼刷新是一個意思啦。這個請求地址正是exampleCaptcha.WebCaptcha.CaptchaImageUrl的屬性值。

看看刷新按鈕最終生成的html是什么樣子的,如下圖,最關鍵的是a標簽的onclick(紅框框起部分),雖然看不到具體方法,但能知道方法的最終結果就是為了完成上面的請求。能理解這個,其它的都可以理解了。

 

其二我並不喜歡在前端寫過多的C#代碼。觀察了一下后端代碼

[CaptchaValidation("CaCode", "ExampleCaptcha", "Incorrect CAPTCHA code!")]

public ActionResult ExampleAction(bool captchaValid)...

對於Action的參數captchaValid我很不解,當我改變參數名稱后就會報錯,想想應該是CaptchaValidationAttribute中得來的吧,覺得用這個Attribute限制太多,不夠靈活。最終我去掉了Attribute,用MvcCaptcha類的靜態方法 MvcCaptcha.Validate(string,string,string),這個重載需要三個參數一個是captcha的Id,一個是用戶輸入值,另一個是validtingInstanceId

對於最后一個參數我開始摸不着北,后面在html源碼中找到個hidden的input,只是感覺像是它,因為它有name屬性,憑着感覺試了,沒想還真行

 

那么就把后台給改了試試,其實最后個參數的值就是exampleCaptcha.CurrentInstanceId這個屬性值(有時我自己覺得我有點傻的可愛),這樣一來問題一就解決了部分問題,可以不用在前端寫那么多C#代碼了,並且每次登陸頁面都要輸入對的驗證碼才能ok。

復制代碼
public ActionResult ExampleAction(string CaCode, string BDC_VCID_ExampleCaptcha)
        {
            string instaneId = CustomCaptcha.CurrentInstanceId;
            bool captchaValid= MvcCaptcha.Validate("ExampleCaptcha", CaCode,BDC_VCID_ExampleCaptcha);
            if (captchaValid)
                return Content("ok");
            return Content("no");
        }
復制代碼

 

問題二

解決問題二我用的辦法很粗暴,我后來重做了一個MVC項目,做了一個完整的登陸頁面,那個刷新和聲音按鈕我不好布局,直接給隱藏了,既然它粗暴的讓改屬性值不能改變驗證圖片的點擊鏈接,我又不能說讓用戶點圖片進入一個外國網站,那么我也只能粗暴通過jquery來解決問題,我想的辦法就是把前面關於刷新按鈕的a標簽的onclick給圖片中a標簽的onclick,簡單粗暴。

雖然兩個問題並沒有完美解決,但感覺自己還在挺努力的。所以最后把修改的全部代碼貼上吧

最終效果

 

前端

View Code

 

后端專門寫了一個類,有一個靜態屬性,用於指定當前驗證碼的實例Id,一個靜態方法,用於自定義captcha

復制代碼
using BotDetect.Web.Mvc;

namespace OADemo.MVCApp
{
    public class CustomCaptcha
    {
        /// <summary>
        /// 當前驗證碼的實例Id
        /// </summary>
        public static string CurrentInstanceId { get { return currentInstanceId; } }
        private static string currentInstanceId;
        public static MvcCaptcha GetCaptcha(string captchaId)
        {
            MvcCaptcha exampleCaptcha = new MvcCaptcha(captchaId);
            exampleCaptcha.ImageStyle = BotDetect.ImageStyle.CaughtInTheNet2;
            exampleCaptcha.ReloadEnabled = false;
            exampleCaptcha.SoundEnabled = false;
            currentInstanceId = exampleCaptcha.CurrentInstanceId;
            return exampleCaptcha;
        }
        /// <summary>
        /// 獲取自定義的驗證碼樣式
        /// </summary>
        /// <param name="captchaId"></param>
        /// <param name="width">指定驗證碼圖片的寬度</param>
        /// <param name="height">指定驗證碼圖片的高度</param>
        /// <param name="codeLength">指定驗證碼的個數</param>
        /// <returns></returns>
        public static MvcCaptcha GetCaptcha(string captchaId,int width,int height,int codeLength)
        {
            MvcCaptcha exampleCaptcha = new MvcCaptcha(captchaId);
            exampleCaptcha.ImageStyle = BotDetect.ImageStyle.CaughtInTheNet2;//我個人喜歡的風格
            exampleCaptcha.ReloadEnabled = false;//去掉刷新的按鈕
            exampleCaptcha.SoundEnabled = false;//去掉聲音播放按鈕
            exampleCaptcha.CodeLength = codeLength;//指定驗證碼的長度
            exampleCaptcha.ImageSize = new System.Drawing.Size(width,height);//指定圖片的大小
            currentInstanceId = exampleCaptcha.CurrentInstanceId;//當前實例的id
            return exampleCaptcha;
        }
    }
}
復制代碼

 

后端控制器代碼

Controller Code

 

 

好吧,后端控制器代碼應該是這樣才對的

復制代碼
using System.Web.Mvc;

namespace OADemo.MVCApp.Controllers
{
    public class LoginController : Controller
    {

        // GET: Login
        public ActionResult Index()
        {
            return View();
        }
        public ActionResult Account(string CaptchaCode, string username, string password)
        {
            string instaneId = CustomCaptcha.CurrentInstanceId;
            bool captchaValid= MvcCaptcha.Validate("ExampleCaptcha", CaptchaCode,instaneId);
            if (captchaValid)
                return Content("ok");
            return Content("no");
        }
    }
}
復制代碼

 

 

目前就寫到這里了,當然后面的驗證還沒寫,還只是在測試captcha階段,所以想說要源碼的同志,就不要費力了,因為這里忘記密碼和注冊都沒有寫的。這一篇完全只是寫的我目前對captcha的研究,也許在眾多的MvcCaptcha類的事件中,才是真正有效解決問題的辦法,只是我沒有英文水平,加上現在時間太晚,眼睛和腦袋受不了,暫告一段落,事件這么多呢,搞懂了,webconfig配置都可以自定義

復制代碼
 public static event EventHandler<GeneratedCaptchaCodeEventArgs> GeneratedCaptchaCode;
        public static event EventHandler<GeneratedCaptchaImageEventArgs> GeneratedCaptchaImage;
        public static event EventHandler<GeneratedCaptchaSoundEventArgs> GeneratedCaptchaSound;
        public static event EventHandler<GeneratingCaptchaCodeEventArgs> GeneratingCaptchaCode;
        public static event EventHandler<GeneratingCaptchaImageEventArgs> GeneratingCaptchaImage;
        public static event EventHandler<GeneratingCaptchaSoundEventArgs> GeneratingCaptchaSound;
        public static event EventHandler<InitializedWebCaptchaEventArgs> InitializedWebCaptcha;
        public static event EventHandler<ValidatedUserInputEventArgs> ValidatedUserInput;
        public static event EventHandler<ValidatingUserInputEventArgs> ValidatingUserInput;
復制代碼

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM