پیاده سازی تصویر امنیتی (کپچا) در برنامه نویسی اندروید

پیاده سازی تصویر امنیتی (کپچا) در برنامه نویسی اندرویدReviewed by آریانا on Dec 3Rating: 5.0پیاده سازی تصویر امنیتی (کپچا) در برنامه نویسی اندرویدکد امنیتی (کپچا) یکی از روش های تأیید هویت است که ثابت می کند شما یک ربات نیستید.

کد امنیتی (کپچا) یکی از روش های تأیید هویت است که ثابت می کند شما یک ربات نیستید. در ویکی پدیا کد امنیتی (کپچا)  به صورت زیر تعریف می شود:

“کپچا به انگلیسی (CAPTCHA) :که سرنام برابر انگلیسی «آزمون همگانی کاملاً خودکارشدهٔ تورینگ برای مجزا کردن انسان و رایانه» است، یک سامانهٔ امنیتی و روند ارزیابی است که برای جلوگیری از برخی حمله‌های خرابکارانهٔ ربات‌های اینترنتیبه‌کار می‌رود. جای‌گزین آزترا که سرنام «آزمون تورینگ تشخیص رایانه از انسان» است هم برای کپچا دیده شده است. این روند می‌تواند مشخص کند که مراجعه کنندگان به یک وب‌گاه و یا سایر خدمات آنلاین انسان هستند یا کامپیوتر. بدین منظور برنامهٔ کپچا آزمون‌هایی را تولید می‌کند که تنها انسان‌ها قادر به پاسخ‌گویی به آنها باشند. چون کامپیوترها و نرم‌افزارهای فعلی احتمالاً  نمی‌توانند پاسخ درستی به این آزمون بدهند، هر کاربری که آنرا درست حل کند، انسان فرض می‌شود.”

در واقع کپچا می خواهد تشخیص دهد که کاربر یک انسان است یا نه؟

در توسعه وب، کپچا یک موضوع بسیار محبوب است و پیاده سازی آن در یک پروژه وب بسیار ساده است. اما در برنامه نویسی موبایل به طور کلی و آندروید به طور خاص، پیاده سازی تصویر امنیتی (کپچا) کار چندان آسانی نیست.

در این پست، من راهی را برای ساخت یک “تصویر بیت مپ کپچا ” که می تواند به شما در “توسعه صفحه نمایش احراز هویت” (captcha bitmap image) کمک کند ارائه  می دهم.

captcha-bitmap-image

ایجاد متن و محاسبات ریاضی کلاس تصویر امنیتی کپچا

۲ نوع تصویر امنیتی(کپچا) معمول و محبوب وجود دارد: متنی(text) و اپراتور ریاضی(math operator)

ما تم و نمایش آنها را به صورت تصویر بیتمپ ایجاد خواهیم کرد.

حالا لطفا این ۳ کلاس را که “تصویر امنیتی بیت مپ” (captcha bitmap) را به پروژه شما اضافه می کند در پروژه تان کپی نمایید:

Captcha.java

[code]

package info.devexchanges.androidcaptcha;

 

import java.util.List;

import java.util.Random;

 

import android.graphics.Bitmap;

import android.graphics.Color;

 

public abstract class Captcha {

protected Bitmap image;

protected String answer = “”;

private int width;

protected int height;

protected int x = 0;

protected int y = 0;

protected static List usedColors;

 

protected abstract Bitmap image();

 

public static int color(){

Random r = new Random();

int number;

do{

number = r.nextInt(9);

}while(usedColors.contains(number));

usedColors.add(number);

switch(number){

case 0: return Color.BLACK;

case 1: return Color.BLUE;

case 2: return Color.CYAN;

case 3: return Color.DKGRAY;

case 4: return Color.GRAY;

case 5: return Color.GREEN;

case 6: return Color.MAGENTA;

case 7: return Color.RED;

case 8: return Color.YELLOW;

case 9: return Color.WHITE;

default: return Color.WHITE;

}

}

 

public int getWidth(){

return this.width;

}

 

public void setWidth(int width){

if(width > 0 && width < 10000){

this.width = width;

}else{

this.width = 300;

}

}

 

public int getHeight(){

return this.height;

}

 

public void setHeight(int height){

if(height > 0 && height < 10000){

this.height = height;

}else{

this.height = 100;

}

}

 

public Bitmap getImage() {

return this.image;

}

 

public boolean checkAnswer(String ans) {

return ans.equals(this.answer);

}

}

[/code]

TextCaptcha.java

[code]

package info.devexchanges.androidcaptcha;

 

import java.io.CharArrayWriter;

import java.util.ArrayList;

import java.util.Random;

 

import android.graphics.Bitmap;

import android.graphics.Canvas;

import android.graphics.LinearGradient;

import android.graphics.Paint;

import android.graphics.Shader;

import android.graphics.Bitmap.Config;

 

public class TextCaptcha extends Captcha {

 

protected TextOptions options;

private int wordLength;

private char mCh;

 

public enum TextOptions {

UPPERCASE_ONLY,

LOWERCASE_ONLY,

NUMBERS_ONLY,

LETTERS_ONLY,

NUMBERS_AND_LETTERS

}

 

public TextCaptcha(int wordLength, TextOptions opt) {

new TextCaptcha(0, 0, wordLength, opt);

}

 

public TextCaptcha(int width, int height, int wordLength, TextOptions opt) {

setHeight(height);

setWidth(width);

this.options = opt;

usedColors = new ArrayList<>();

this.wordLength = wordLength;

this.image = image();

}

 

@Override

protected Bitmap image() {

LinearGradient gradient = new LinearGradient(0, 0, getWidth() / this.wordLength, getHeight() / 2, color(), color(), Shader.TileMode.MIRROR);

Paint p = new Paint();

p.setDither(true);

p.setShader(gradient);

Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888);

Canvas c = new Canvas(bitmap);

c.drawRect(0, 0, getWidth(), getHeight(), p);

Paint tp = new Paint();

tp.setDither(true);

tp.setTextSize(getWidth() / getHeight() * 20);

 

Random r = new Random(System.currentTimeMillis());

CharArrayWriter cab = new CharArrayWriter();

this.answer = “”;

for (int i = 0; i < this.wordLength; i++) {

char ch = ‘ ‘;

switch (options) {

case UPPERCASE_ONLY:

ch = (char) (r.nextInt(9165) + (65));

break;

case LOWERCASE_ONLY:

ch = (char) (r.nextInt(12397) + (97));

break;

case NUMBERS_ONLY:

ch = (char) (r.nextInt(5849) + (49));

break;

case LETTERS_ONLY:

ch = getLetters(r);

break;

case NUMBERS_AND_LETTERS:

ch = getLettersNumbers(r);

break;

default:

ch = getLettersNumbers(r);

break;

}

cab.append(ch);

this.answer += ch;

}

 

char[] data = cab.toCharArray();

for (int i = 0; i < data.length; i++) {

this.x += (30 – (3 * this.wordLength)) + (Math.abs(r.nextInt()) % (65 – (1.2 * this.wordLength)));

this.y = 50 + Math.abs(r.nextInt()) % 50;

Canvas cc = new Canvas(bitmap);

tp.setTextSkewX(r.nextFloat() – r.nextFloat());

tp.setColor(color());

cc.drawText(data, i, 1, this.x, this.y, tp);

tp.setTextSkewX(0);

}

return bitmap;

}

 

private char getLetters(Random r) {

int rint = (r.nextInt(12365) + (65));

if (((rint > 90) && (rint < 97)))

getLetters(r);

else

mCh = (char) rint;

return mCh;

}

 

private char getLettersNumbers(Random r) {

int rint = (r.nextInt(12349) + (49));

 

if (((rint > 90) && (rint < 97)))

getLettersNumbers(r);

else if (((rint > 57) && (rint < 65)))

getLettersNumbers(r);

else

mCh = (char) rint;

return mCh;

}

}

[/code]

MathCaptcha.java

[code]

package info.devexchanges.androidcaptcha;

 

import java.util.ArrayList;

import java.util.Random;

 

import android.graphics.Bitmap;

import android.graphics.Bitmap.Config;

import android.graphics.Canvas;

import android.graphics.LinearGradient;

import android.graphics.Paint;

import android.graphics.Shader;

 

public class MathCaptcha extends Captcha {

 

protected MathOptions options;

 

public enum MathOptions{

PLUS_MINUS,

PLUS_MINUS_MULTIPLY

}

 

public MathCaptcha(int width, int height, MathOptions opt){

this.height = height;

setWidth(width);

this.options = opt;

usedColors = new ArrayList<>();

this.image = image();

}

 

@Override

protected Bitmap image() {

int one = 0;

int two = 0;

int math = 0;

 

LinearGradient gradient = new LinearGradient(0, 0, getWidth() / 2, this.height / 2, color(), color(), Shader.TileMode.MIRROR);

Paint p = new Paint();

p.setDither(true);

p.setShader(gradient);

Bitmap bitmap = Bitmap.createBitmap(getWidth(), this.height, Config.ARGB_8888);

Canvas c = new Canvas(bitmap);

c.drawRect(0, 0, getWidth(), this.height, p);

 

LinearGradient fontGrad = new LinearGradient(0, 0, getWidth() / 2, this.height / 2, color(), color(), Shader.TileMode.CLAMP);

Paint tp = new Paint();

tp.setDither(true);

tp.setShader(fontGrad);

tp.setTextSize(getWidth() / this.height * 20);

Random r = new Random(System.currentTimeMillis());

one = r.nextInt(9) + 1;

two = r.nextInt(9) + 1;

math = r.nextInt((options == MathOptions.PLUS_MINUS_MULTIPLY)?3:2);

if (one < two) {

Integer temp = one;

one = two;

two = temp;

}

 

switch (math) {

case 0:

this.answer = (one + two) + “”;

break;

case 1:

this.answer = (one – two) + “”;

break;

case 2:

this.answer = (one * two) + “”;

break;

}

char[] data = new char[]{String.valueOf(one).toCharArray()[0], oper(math), String.valueOf(two).toCharArray()[0]};

for (int i=0; i

[/code]

من این کلاس ها را از Android-Easy-Captcha project  در Github گرفته ام و برخی مشکلات کد آن را برطرف کرده ام:

طریقه استفاده در اکتیویتی/فرگمنت ( Activity/Fragment )

همانطور که می بینید، ما در ساختار بالا می توانیم به راحتی یک متن جدید(new text) یا کپچای ریاضی(math captcha) را مقداردهی اولیه کنیم.

[code]

TextCaptcha textCaptcha = new TextCaptcha(600, 150, 4, TextCaptcha.TextOptions.LETTERS_ONLY);

MathCaptcha mathCaptcha = new MathCaptcha(600, 150, MathCaptcha.MathOptions.PLUS_MINUS);

[/code]

در حال حاضر شما یک تصویر بیتمپ(Bitmap) با اندازه ی ۱۵۰*۶۰۰ پیکسل دارید. به منظور نمایش آن در ImageView تنها نیاز دارید متد() getImage (که بازگشت به Bitmap object هست) را درخواست کنید:

[code]

imageView.setImageBitmap(textCaptcha.getImage());

imageView1.setImageBitmap(mathCaptcha.getImage());

[/code]

captcha image ممکن است به شبیه به تصویر زیر باشد:

captcha-image

بررسی و چک کردن ورودی های کاربران

با استفاده از متد checkAnswer() method ، ما می توانیم چک کنیم که کاربر اطلاعات را درست وارد کرده یا غلط (از EditText )  با استفاده از captcha value :

[code]

                //checking text captcha

if (!textCaptcha.checkAnswer(edtTextCaptcha.getText().toString().trim())) {

edtTextCaptcha.setError(“Captcha is not match”);

numberOfCaptchaFalse++;

} else {

Log.d(“Main”, “captcha is match!”);

}

[/code]

البته این خروجی یک نمونه از زمانی است که کاربر مقداری اشتباه را وارد کرده است:

android-captcha-image

یک نکته مهم: به طور پیش فرض text captcha حروف بزرگ و کوچک را از یکدیگر متمایز می کند.  شما می توانید خروجی خود را هنگامی که کاربر مقدار درستی را وارد کرده، به سادگی با یک Toast  شبیه عکس زیر نمایش دهید.

android -captcha-image

نتیجه گیری

در حال حاضر شما یک راه برای ایجاد کچپای متنی یا کپچای ریاضی در اندروید و نحوه اعمال آن به پروژه ی خودتان را  یاد گرفته اید. امیدوارم این پست به شما در مسئله ی احراز هویت در پروژه اندرویدی تان کمک کند و مفید واقع شود.

پاسخ دهید