So I tried creating the system.
Captcha.cs
put dll file in bin folder after doing build the project on vs2010.
This requires the following resources in the project.
Font as File (*** The font has to be used under the EULA(End User License Agreement) or something. anyway, you should ask the font vender or the copyright owner. ***)
SESSION_KEY_NAME as string (ex. value = "CaptchaSessionKey")
CAPTCHA_CODE_STRING as string (ex. value = "1234567890")
using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.Drawing.Text; using System.IO; using System.Runtime.InteropServices; using System.Web; using System.Web.SessionState; namespace CaptchaLibrary { public sealed class Captcha : IDisposable { private readonly Random _random = new Random(); private bool _disposed = false; private Bitmap Image { get; set; } private PrivateFontCollection PFC { set; get; } private IntPtr Ptr { set; get; } public Captcha(int width, int height) { string text = GenerateCaptchaCode(5); if (width > 0 && height > 0) { HttpContext.Current.Session[Properties.Resources.SESSION_KEY_NAME] = text; this.CreateBitmapImage(text, width, height); } } ~Captcha() { Dispose(false); } public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } private void Dispose(bool disposing) { lock (this) { if (!this._disposed) { if (disposing) { if (this.Image != null) { this.Image.Dispose(); this.Image = null; } if (this.PFC != null) { this.PFC.Dispose(); this.PFC = null; } if (this.Ptr != IntPtr.Zero) { Marshal.FreeHGlobal(this.Ptr); this.Ptr = IntPtr.Zero; } } } _disposed = true; } } public static bool Validate(string tagName) { bool isValid = false; ValidationErrorMessage = null; if (string.IsNullOrEmpty(tagName)) throw new ArgumentNullException("tagName", "対象となるタグ名が指定されていません。"); string paramValue = HttpContext.Current.Request.Form[tagName]; if (string.IsNullOrEmpty(paramValue)) ValidationErrorMessage = "認証コードを入力してください。"; string sessionValue = HttpContext.Current.Session[Properties.Resources.SESSION_KEY_NAME].ToString(); if (string.IsNullOrEmpty(sessionValue)) ValidationErrorMessage = "タイムアウトです。再読み込みして、認証コードを生成しなおしてください。"; if (string.IsNullOrEmpty(ValidationErrorMessage)) { if (sessionValue.Equals(paramValue)) isValid = true; else ValidationErrorMessage = "認証コードが違います。"; } HttpContext.Current.Session.Remove(Properties.Resources.SESSION_KEY_NAME); return isValid; } public static string ValidationErrorMessage { private set; get; } public void OutputAsJpg() { HttpContext.Current.Response.Clear(); HttpContext.Current.Response.ContentType = "image/jpg"; HttpContext.Current.Response.Flush(); if (Image != null) this.Image.Save(HttpContext.Current.Response.OutputStream, ImageFormat.Jpeg); HttpContext.Current.Response.End(); } private void CreateBitmapImage(string code, int width, int height) { this.Image = new Bitmap(width, height, PixelFormat.Format32bppArgb); try { using (Graphics g = Graphics.FromImage(this.Image)) { g.SmoothingMode = SmoothingMode.AntiAlias; Rectangle rect = new Rectangle(0, 0, width, height); DrawBackground(g, rect); DrawText(g, rect, code, true); DrawRandomNoise(g, rect); DrawRandomLines(g, rect, 2); } } catch (Exception) { this.Image = null; } } private void DrawBackground(Graphics g, Rectangle rect) { using (HatchBrush brush = new HatchBrush(HatchStyle.SmallConfetti, Color.LightGray, Color.WhiteSmoke)) g.FillRectangle(brush, rect); } private void DrawText(Graphics g, Rectangle rect, string code, bool isWarp) { Font font = null; try { using (GraphicsPath path = new GraphicsPath()) using (HatchBrush brush = new HatchBrush(HatchStyle.LargeConfetti, Color.LightGray, Color.DarkGray)) { SizeF size; float fontSize = rect.Height + 1; FontFamily ff = GetFontFamily(); do { fontSize--; font = new Font(ff, fontSize, FontStyle.Bold); size = g.MeasureString(code, font); } while (size.Width > rect.Width); if (ff != null) { ff.Dispose(); ff = null; } StringFormat format = new StringFormat(); format.Alignment = StringAlignment.Center; format.LineAlignment = StringAlignment.Center; path.AddString(code, font.FontFamily, (int)font.Style, font.Size, rect, format); if (isWarp) { PointF[] points = { new PointF(this._random.Next(rect.Width) / 5F, this._random.Next(rect.Height) / 5F), new PointF(rect.Width - this._random.Next(rect.Width) / 5F, this._random.Next(rect.Height) / 5F), new PointF(this._random.Next(rect.Width) / 5F, rect.Height - this._random.Next(rect.Height) / 5F), new PointF(rect.Width - this._random.Next(rect.Width) / 5F, rect.Height - this._random.Next(rect.Height) / 5F) }; Matrix matrix = new Matrix(); matrix.Translate(0F, 0F); path.Warp(points, rect, matrix, WarpMode.Perspective, 0F); } g.FillPath(brush, path); } } finally { if (font != null) { font.Dispose(); font = null; } } } private void DrawRandomNoise(Graphics g, Rectangle rect) { using (HatchBrush brush = new HatchBrush(HatchStyle.SmallConfetti, Color.LightGray, Color.DarkGray)) { int max = Math.Max(rect.Width, rect.Height); for (int i = 0; i < (int)(rect.Width * rect.Height / 10F); i++) { int x = this._random.Next(rect.Width); int y = this._random.Next(rect.Height); int w = this._random.Next(max / 50); int h = this._random.Next(max / 50); g.FillEllipse(brush, x, y, w, h); } } } private void DrawRandomLines(Graphics g, Rectangle rect, int lines) { using (HatchBrush brush = new HatchBrush(HatchStyle.LargeConfetti, Color.LightGray, Color.DarkGray)) using (Pen pen = new Pen(brush, 2)) { for (int i = 0; i < lines; i++) { float x = 0L; float y = _random.Next(rect.Height); PointF points = new PointF(x, y); PointF pointe = new PointF(rect.Width - x, rect.Height - y); g.DrawLine(pen, points, pointe); } } } private string GenerateCaptchaCode(int length) { string captchaCode = Properties.Resources.CAPTCHA_CODE_STRING; if (length < 0) length = 5; string code = ""; for (int i = 0; i < length; i++) code = String.Concat(code, captchaCode.Substring(_random.Next(captchaCode.Length), 1)); return code; } private FontFamily GetFontFamily() { try { byte[] bytes = Properties.Resources.Font; this.PFC = new PrivateFontCollection(); this.Ptr = Marshal.AllocHGlobal(Marshal.SizeOf(bytes[0]) * bytes.Length); Marshal.Copy(bytes, 0, this.Ptr, bytes.Length); this.PFC.AddMemoryFont(this.Ptr, bytes.Length); return this.PFC.Families[0]; } catch (Exception) { return System.Drawing.FontFamily.GenericSerif; } } } }
CaptchaImage.cshtml
@using CaptchaLibrary; @{ var captchaImg = new Captcha(240,50); captchaImg.OutputAsJpg(); captchaImg.Dispose(); }
CaptchaControlPanel.cshtml
Put this file in App_Code folder
@helper Show(string tagName, string errorMsg ){
<div id="captcha">
<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.4.4.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$('#captcha_inputtag_reloadbutton').click(function(){
$.ajax({
type: 'GET',
cache: false,
success: function(msg, status){
$('#captcha_imgtag_captchaimage').attr('src', '@Href"~/CaptchaImage")?' + new Date().getTime());
return false;
}
});
});
});
</script>
<fieldset style="width: 320px;height: 120px;background-color: #ffffe0;position: relative; top: 0px;left: 0px;">
<legend title="認証コード(CAPTCHA)">画像認証(CAPTCHA)</legend>
<div align="left" style="width:320px;height: 60px;background-color: transparent;position: relative;top: -15px;left: 5px;">
<img id="captcha_imgtag_captchaimage" src="@Href("~/CaptchaImage")" alt="CAPTCHA IMAGE" title="認証用画像(CAPTCHA IMAGE)" />
<input type="image" src="[Image path for reload button]" id="captcha_inputtag_reloadbutton" alt="再読込ボタン" title="再読込ボタン" onclick="return false;" style="width:50px;height:50px;position:relative;top:auto;left:5pt;" /><br />
<strong>上の画像に表示されているコードを入力してください。</strong>
</div>
<div align="left" style="width: 320px;height: 60px;background-color: transparent;position: relative;top: 0px;left: 5px;">
<input type="text" name="@tagName" title="画像認証コード(CAPTCHA Code)入力ボックス" @if(!errorMsg.IsEmpty()){<text>class="error-field"</text>} />
@if (!errorMsg.IsEmpty()) {
<label for="@tagName" class="validation-error" style="position: relative;top: 0px;left: 0px;">
@errorMsg
</label>
}
</div>
</fieldset>
</div>
}
Register.cshtml
@using CaptchaLibrary; @{ if(WebSecurity.IsAuthenticated) { Response.Redirect(Href("~/")); } Response.CacheControl = "no-cache"; Layout = "~/_SiteLayout.cshtml"; Page.Title = "アカウントの登録"; Page.Description = "新規登録フォーム"; var email = ""; var password = ""; var confirmPassword = ""; var isValid = true; var emailErrorMessage = ""; var passwordErrorMessage = ""; var confirmPasswordMessage = ""; var accountCreationErrorMessage = ""; var captchaTextErrorMessage = ""; if (IsPost) { email = Request.Form["email"]; password = Request.Form["password"]; confirmPassword = Request.Form["confirmPassword"]; if (email.IsEmpty()) { emailErrorMessage = "電子メール アドレスを入力してください。"; isValid = false; } if (password.IsEmpty()) { passwordErrorMessage = "パスワードを空白にすることはできません。"; isValid = false; } if (password != confirmPassword) { confirmPasswordMessage = "新しいパスワードと確認のパスワードが一致しません。"; isValid = false; } if(!Captcha.Validate("captchaText")) { captchaTextErrorMessage = Captcha.ValidationErrorMessage; isValid = false; } if (isValid) { var db = Database.Open([db name(w/o ".sdf"]); var user = db.QuerySingle("SELECT Email FROM UserProfile WHERE LOWER(Email) = LOWER(@0)", email); if (user == null) { db.Execute("INSERT INTO UserProfile (Email) VALUES (@0)", email); try { bool requireEmailConfirmation = !WebMail.SmtpServer.IsEmpty(); var token = WebSecurity.CreateAccount(email, password, requireEmailConfirmation); if (requireEmailConfirmation) { var hostUrl = Request.Url.GetComponents(UriComponents.SchemeAndServer, UriFormat.Unescaped); var confirmationUrl = hostUrl + VirtualPathUtility.ToAbsolute("~/Account/Confirm?confirmationCode=" + HttpUtility.UrlEncode(token)); WebMail.Send( to: email, subject: "アカウントを確認してください", body: "確認コード: " + token + "。<a href=\"" + confirmationUrl + "\">" + confirmationUrl + "</a> にアクセスしてアカウントを有効にしてください。" ); } if (requireEmailConfirmation) { Response.Redirect("~/Account/Thanks"); } else { WebSecurity.Login(email, password); Response.Redirect("~/"); } } catch (System.Web.Security.MembershipCreateUserException e) { isValid = false; accountCreationErrorMessage = e.ToString(); } } else { isValid = false; accountCreationErrorMessage = "電子メール アドレスは既に使用中です。"; } } } } <p> 新しいアカウントを作成するには、以下のフォームを使用してください。 </p> @if (!isValid) { <p class="message error"> @if (accountCreationErrorMessage.IsEmpty()) { @:エラーを修正し、再試行してください。 } else { @accountCreationErrorMessage } </p> } <form method="post" action=""> <fieldset> <legend>申し込みフォーム</legend> <ol> <li class="email"> <label for="email">電子メール:</label> <input type="text" id="email" name="email" title="Email address" value="@email" @if(!emailErrorMessage.IsEmpty()){<text>class="error-field"</text>} /> @if (!emailErrorMessage.IsEmpty()) { <label for="email" class="validation-error">@emailErrorMessage</label> } </li> <li class="password"> <label for="password">パスワード:</label> <input type="password" id="password" name="password" title="パスワード" @if(!passwordErrorMessage.IsEmpty()){<text>class="error-field"</text>} /> @if (!passwordErrorMessage.IsEmpty()) { <label for="password" class="validation-error">@passwordErrorMessage</label> } </li> <li class="confirm-password"> <label for="confirmPassword">パスワードの確認入力:</label> <input type="password" id="confirmPassword" name="confirmPassword" title="パスワードの確認入力" @if(!confirmPasswordMessage.IsEmpty()){<text>class="error-field"</text>} /> @if (!confirmPasswordMessage.IsEmpty()) { <label for="confirmPassword" class="validation-error">@confirmPasswordMessage</label> } </li> <li class="recaptcha"> <!-- CAPTCHA Control Panel --> <p> @CaptchaControlPanel.Show("captchaText", @captchaTextErrorMessage) </p> <!-- CAPTCHA Control Panel --> </li> </ol> <p class="form-actions"> <input type="submit" value="登録" title="登録" /> </p> </fieldset> </form>
Register.cshtml |
Error Message 1 |
Error Message 2 |
No comments:
Post a Comment