오도원입니다.

건강과 행복을 위하여

PNU DSC/Solution Challenge

Flask 09. Flask-WTF

오도원공육사 2020. 3. 10. 22:27
반응형

플라스크가 마이크로 프레임워크이므로 기능들이 부족하다. 그래서 form관리를 할 때 쓰는 패키지가 WTF이다. 

 

파이썬에서 form을 만들고 template에 전달에서 form을 표현할 것이다. 이렇게 하면 csrf보호기법, validation을 편하게 할 수 있다.

 

CSRF는 사이트 간 요청 위조를 방지하기 위해서 form안에 암호화된 해쉬키를 넣어놓고 직접 만든 사이트안에서 일어나는 요청인지 아닌지 판별하는 패키지이다.

 

CSRF 해쉬값을 자동으로 전달해서 검증해준다. 

 

1. form.py

form을 관리하는 파일을 따로 만든다.

from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms import PasswordField
from wtforms.validators import DataRequired, EqualTo

class RegisterForm(FlaskForm): # 모델을 생성하는 것과 비슷하다.
	userid = StringField('userid', validators=[DataRequired()])
    username = StringField('username', validators=[DataRequired()])
    password = PasswordField('password', validators=[DataRequired(), EqualTo('repassword')])
    # EqualTo는 비밀번호 확인과 같은지 검사한다.
    repassword = PasswordField('repassword', validators=[DataRequired()])

생성한 form객체가 정보를 받을 때 유효성 검사까지 알아서 해준다.

 

2. register.html

기존의 form 부분을 보면 이런식으로 되어있다.

...
<form method="POST">
  <div class="form-group">
    <label for="userid">아이디</label>
    <input type="text" class="form-control" id="userid" placeholder="아이디" name="userid" />
  </div>
  <div class="form-group">
    <label for="username">사용자 이름</label>
    <input type="text" class="form-control" id="username" placeholder="사용자 이름" name="username" />
  </div>
  <div class="form-group">
    <label for="password">비밀번호</label>
    <input type="password" class="form-control" id="password" placeholder="비밀번호" name="password" />
  </div>
  <div class="form-group">
    <label for="re-password">비밀번호 확인</label>
    <input type="password" class="form-control" id="re-password" placeholder="비밀번호 확인" name="re-password" />
  </div>
  <button type="submit" class="btn btn-primary">등록</button>
</form>
...

이것을 생성한 wtf를 이용한 form 객체 형식에 맞춰 바꾸고, csrf를 추가한다.

...
<form method="POST">
	{{form.csrf_token}}
    <div class="form-group">
    	{{form.userid.label("아이디")}}
        {{form.userid(class="form-control", placeholder="아이디")}}
    </div>
    <div class="form-group">
    	{{form.username.label("사용자 이름")}}
        {{form.username(class="form-control", placeholder="사용자이름")}}
    </div>
    <div class="form-group">
    	{{form.password.label("비밀번호")}}
        {{form.password(class="form-control", placeholder="비밀번호")}}
    </div>
    <div class="form-group">
    	{{form.repassword.label("비밀번호 확인")}}
        {{form.repassword(class="form-control", placeholder="비밀번호 확인")}}
    </div>
    <button type="submit" class="btn btn-primary">등록</button>
</form>
...
    

함수처럼 사용하면돼서 훨씬 간단하고 직관적이다. {{form.csrf_token}} 이것은 csrf를 활성화하는 것이다. 

csrf_token을 통해서 value로 저런 해시값이 들어오고 이것을 통해 사이트 간 요청위조를 판별한다.

 

3. app.py

이제 control부분을 수정한다. form객체에서 POST 메소드 여부와 유효성을 자동으로 검사하므로 훨씬 간단하게 작성할 수 있다.

...
from forms import RegisterForm

...

@app.route('/register', methods=['GET', 'POST'])
def register():
	form = RegisterForm()
    if form.validate_on_submit(): 
    	fcuser = Fcuser()
        fcuser.userid = form.data.get('userid')
        fcuser.username = form.data.get('username')
        fcuser.password = form.data.get('password')
        
        db.session.add(fcuser)
        db.session.commit()
        print('Success!')
        
        return redirect('/')
    return render_template('register.html', form=form)

...

validate_on_submit()함수가 POST요청여부와 요청에 담긴 데이터의 유효성을 자동으로 검사해준다. 그리고 form이 어떤 form인지 form=form으로 명시해준다.

 

그리고 csrf를 사용하기 위해서 app을 설정해줘야한다.

...
if __name__ == "main":
	...
    app.config['SECRET_KEY'] = 'aksldjfalksdj' # 해시값은 아무거나 적었다.
    csrf = CSRFProtect()
    csrf.init_app(app)
    ...

이제 저 해시값을 기준으로 암호화하여 검사한다.

반응형