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