2

演習のためだけにキャプチャを作成しています。キャプチャ画像の作成は問題ないようです。しかし、ユーザーが入力したキャプチャ チャレンジを検証しようとするたびに、次のキャプチャに対して検証が行われます。私はこれをどうするかで立ち往生しています。キャプチャ画像作成機能 - captcha.py

import random
import Image
import ImageFont
import ImageDraw
import ImageFilter
import JpegImagePlugin
import PngImagePlugin


def gen_captcha(text, fnt, fnt_sz, file_name, fmt='JPEG'):
fgcolor = random.randint(0,0xff0000)
bgcolor = fgcolor ^ 0xffffff
font = ImageFont.truetype(fnt,fnt_sz)
dim = font.getsize(text)
im = Image.new('RGB', (dim[0]+5,dim[1]+5), bgcolor)
d = ImageDraw.Draw(im)
x, y = im.size
r = random.randint
for num in range(100):
    d.rectangle((r(0,x),r(0,y),r(0,x),r(0,y)),fill=r(0,0xffff00))
d.text((3,3), text, font=font, fill=fgcolor)
im = im.filter(ImageFilter.EDGE_ENHANCE_MORE)
im.save(file_name)

views.py からのサインアップ関数

@app.route('/signup', methods = ['GET', 'POST'])
def signup():
if g.user is not None and g.user.is_authenticated():
    return redirect(url_for('index'))

words = open('app/corncob_caps.txt').readlines()
captcha_word = words[random.randint(1,len(words))]
captcha_filename = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(10)) + '.jpg'
captcha.gen_captcha(captcha_word.strip(), 'app/os.ttf', 25, 'app/static/' + captcha_filename + '')


form = SignUpForm(captcha_word)

if form.validate_on_submit() == False:
    return render_template('signup.html', form = form, filename = captcha_filename)
else:
    user = User(form.email.data, form.password.data)
    db.session.add(user)
    db.session.commit()
    flash('You have successfully signed up.')
    flash('You may login now.')
    return redirect(url_for('login'))

return render_template('signup.html', form = form, filename = captcha_filename)

captcha_word をフォーム クラスに渡しています。フォーム クラスは次のとおりです。

class SignUpForm(Form):
email = EmailField('Email Address', validators = [email()])
password = PasswordField('Password', validators = [Required('Please enter a valid password between 8 and 30 characters.'), Length(min = 8, max = 30)])
captcha = TextField('Captcha', validators = [Required('You must enter the challenge captcha.')])
submit = SubmitField('Create Account')
captcha_word = ''

def __init__(self, word, *args, **kwargs):
    Form.__init__(self, *args, **kwargs)
    self.get_word(word)

def get_word(self, word):
    self.captcha_word = word

def validate(self):
    if not Form.validate(self):
        return False
    elif self.captcha_word != self.captcha.data.upper():
        print self.captcha_word
        print self.captcha.data.upper()
        self.captcha.errors.append("Wrong captcha!")
        return False

    user = self.get_user()
    if user:
        self.email.errors.append("That email is already taken.")
        return False
    else:
        return True

def get_user(self):
    return User.query.filter_by(email = self.email.data.lower()).first()

内部に 2 つの print ステートメントを挿入して、比較がうまくいかない理由を確認しました。最初の印刷では次のキャプチャがprint self.captcha.data.upper()表示されましたが、表示された印刷ではユーザーが入力したデータが表示されました。

よくわかりませんが、サインアップ ルートが 2 回呼び出されているようです。しかし、これを修正する方法がわかりません。何か案は?

4

1 に答える 1

4

キャプチャを使用する必要がある場合は、Flask-WTF に既に組み込まれている機能を使用して、車輪を再発明する手間を省くことができます。

車輪を再発明したい場合、主な問題は、ユーザーがフォームを送信するときにキャプチャを再作成していることです。古い値を覚えて参照する方法がありません。

したがって、これが現時点での動作方法です。

  • ユーザーがサインインし、キャプチャを生成すると、フォームを送信していないため、キャプチャ画像を含むサインイン フォームが表示されます。
  • ユーザーがフォームに入力して送信ボタンを押す - これにより、サインアップ ビューが再度読み込まれ、新しいランダム キャプチャが作成され、フォームが送信されたロジック パスをたどるので、ユーザーのキャプチャ データを現在のキャプチャ データと比較すると、一致します。

したがって、永続性が失われています。最初のラウンドで生成したキャプチャはどこにも保持されないため、ユーザーが送信したときにそれを参照する方法がありません。そのため、そのキャプチャ ワードをどこかに保存する必要があります。そのキャプチャ ワードをユーザーのセッションに保存し、それを使用して必要なときに検証したり、危険で署名しフォーム自体に隠しフィールドとして保存したりできますか?

コード例:

これはコードを取得し、値をセッションに保存するために少し調整するだけです-テストされておらず、間違いなく改善される可能性がありますが、機能するはずです:

@app.route('/signup', methods = ['GET', 'POST'])
def signup():

    if g.user is not None and g.user.is_authenticated():
        return redirect(url_for('index'))

    if request.method == 'post':
        captcha_word = session["captcha"]
    else:
        words = open('app/corncob_caps.txt').readlines()
        captcha_word = words[random.randint(1,len(words))]
        session["captcha"] = captcha_word
        captcha_filename = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(10)) + '.jpg'
        captcha.gen_captcha(captcha_word.strip(), 'app/os.ttf', 25, 'app/static/' + captcha_filename + '')


    form = SignUpForm(captcha_word)

    if form.validate_on_submit() == False:
        return render_template('signup.html', form = form, filename = captcha_filename)
    else:
        user = User(form.email.data, form.password.data)
        db.session.add(user)
        db.session.commit()
        flash('You have successfully signed up.')
        flash('You may login now.')
        return redirect(url_for('login'))

    return render_template('signup.html', form = form, filename = captcha_filename)
于 2013-10-23T15:41:35.230 に答える