์ƒˆ์†Œ์‹

๐Ÿ ํŒŒ์ด์ฌ (Python)

ํ”Œ๋ผ์Šคํฌ (Flask) - ํšŒ์›๊ฐ€์ž… ๊ธฐ๋Šฅ ๋งŒ๋“ค๊ธฐ 2 (flask - WTF ์ด์šฉํ•˜๊ธฐ)

  • -

*Flask - WTF 

  • ์„ค์น˜ pip install flask-WTF
  • flask์˜ form์„ ๊ด€๋ฆฌํ• ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ ์ œ๊ณต.
  • CSRF( Cross-site request forgery) protect 
  • ์œ ํšจ์„ฑ ๊ฒ€์ฆ(validation)

 

1. csrf protect

from flask_wtf.csrf import CSRFprotect



if __name__ == "__main__":
	app.config['SECRET_KEY'] = 'wcsfeufhwiquehfdx' 
	csrf = CSRFProtect()
	csrf.init_app(app)

 

์‹œํฌ๋ฆฟ ํ‚ค๋ฅผ ์„ค์ •ํ•ด์ฃผ๊ณ , (์œ„์—๋Š” ์ž„์˜๋กœ ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.) csrf ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  app์„ํ†ตํ•ด ์ดˆ๊ธฐํ™”ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

2. form, Validators, StringField, PasswordField

from flask_wtf import FlaskForm

from wtforms import StringField, 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('re_password')]) #equalTo("ํ•„๋“œ๋„ค์ž„")
    re_password = PasswordField('re_password', validators=[DataRequired()])


FlaskForm : ํผ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. html์—์„œ๋„ from์„ ํ†ตํ•ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

StringField, PasswordField : ๋ฌธ์ž ๊ทธ๋Œ€๋กœ์ž…๋‹ˆ๋‹ค. ์–ด๋– ํ•œ ํ˜•์‹์œผ๋กœ ์ž๋ฃŒ๋ฅผ ๋‹ค๋ฃฐ์ง€ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. PasswordField๋กœ ์„ค์ •ํ•˜๋ฉด *********์™€ ๊ฐ™์€ ํ˜•์‹์œผ๋กœ ์™ธ๋ถ€์—๋Š” ๋ฌธ์ž๊ฐ€ ๋ณด์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ ๋“ค์–ด๊ฐ€๋ฉด ์ผ๋ฐ˜์ ์ธ ๋ฌธ์ž๋กœ ํ™•์ธ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

EqualTo : password ์™€ re_password๊ฐ€ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธ ํ•ฉ๋‹ˆ๋‹ค. ์ด์ „ ํฌ์ŠคํŒ…์—์„œ๋Š” if password==re_password : ์™€ ๊ฐ™์ด ์ง์ ‘ ์กฐ๊ฑด๋ฌธ์„ ํ†ตํ•ด ๊ฒ€์ฆํ–ˆ์ง€๋งŒ EqualTo๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์กฐ๊ฑด๋ฌธ์ด ํ•„์š” ์—†์–ด์ง‘๋‹ˆ๋‹ค.

DataRequired : ๊ณต๋ฐฑ์œผ๋กœ ์ž…๋ ฅ๋˜์ง€ ์•Š์•˜๋Š”์ง€, ๋ฐ์ดํ„ฐ๊ฐ€ ์ž…๋ ฅ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๋ฐ์ดํ„ฐ๊ฐ€ ์ž…๋ ฅ๋˜์ง€ ์•Š์€์ฑ„๋กœ POST๋œ๋‹ค๋ฉด ๋ฐ‘์˜ ๊ทธ๋ฆผ์ฒ˜๋Ÿผ "์ด ์ž…๋ ฅ๋ž€์„ ์ž‘์„ฑํ•˜์„ธ์š”."๋ผ๊ณ  ๋ฉ”์‹œ์ง€๊ฐ€ ๋œน๋‹ˆ๋‹ค.

 


 

*๊ตฌ์กฐ (Structure)

Flaskํด๋”
โ”‚   โ”œโ”€โ”€ templates (ํด๋”)
โ”‚          โ”œโ”€โ”€ register.html                                    
โ”‚          
โ”‚
โ”œโ”€โ”€ app.py (์‹คํ–‰ํŒŒ์ผ)                                           
โ”œโ”€โ”€ db.sqlite (์ด๊ฑด ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋จ)
โ”œโ”€โ”€ models.py

โ”œโ”€โ”€ forms.py

*models.py

##๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ๊ด€๋ จ๋œ ์ฝ”๋“œ

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()           #SQLAlchemy๋ฅผ ์‚ฌ์šฉํ•ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ €์žฅ

class Fcuser(db.Model): 
    __tablename__ = 'fcuser'   #ํ…Œ์ด๋ธ” ์ด๋ฆ„ : fcuser
    id = db.Column(db.Integer, primary_key = True)   #id๋ฅผ ํ”„๋ผ์ด๋จธ๋ฆฌํ‚ค๋กœ ์„ค์ •
    password = db.Column(db.String(64))     #ํŒจ์Šค์›Œ๋“œ๋ฅผ ๋ฐ›์•„์˜ฌ ๋ฌธ์ž์—ด๊ธธ์ด 
    userid = db.Column(db.String(32))       #์ดํ•˜ ์œ„์™€ ๋™์ผ
    username = db.Column(db.String(8))

*app.py

import os #์ ˆ๋Œ€๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•˜๊ธฐ ์œ„ํ•œ Os๋ชจ๋“ˆ ์ž„ํฌํŠธ
from flask import Flask
from flask import request #ํšŒ์›์ •๋ณด ์ œ์ถœํ–ˆ์„๋•Œ ๋ฐ›์•„์˜ค๊ธฐ ์œ„ํ•œ request, post์š”์ฒญ์„ ํ™œ์„ฑํ™”์‹œํ‚ค๊ธฐ ์œ„ํ•จ
from flask import redirect   #ํŽ˜์ด์ง€ ์ด๋™์‹œํ‚ค๋Š” ํ•จ์ˆ˜
from flask import render_template
from models import db
from models import Fcuser #๋ชจ๋ธ์˜ ํด๋ž˜์Šค ๊ฐ€์ ธ์˜ค๊ธฐ.

from flask_wtf.csrf import CSRFProtect
from forms import RegisterForm

app = Flask(__name__)

@app.route('/register', methods=['GET','POST'])  #๊ฒŸ, ํฌ์ŠคํŠธ ๋ฉ”์†Œ๋“œ ๋‘˜๋‹ค ์‚ฌ์šฉ
def register():   #get ์š”์ฒญ ๋‹จ์ˆœํžˆ ํŽ˜์ด์ง€ ํ‘œ์‹œ post์š”์ฒญ ํšŒ์›๊ฐ€์ž…-๋“ฑ๋ก์„ ๋ˆŒ๋ €์„๋•Œ ์ •๋ณด ๊ฐ€์ ธ์˜ค๋Š”๊ฒƒ
    form = RegisterForm()
    if form.validate_on_submit(): # POST๊ฒ€์‚ฌ์˜ ์œ ํšจ์„ฑ๊ฒ€์‚ฌ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์ž…๋ ฅ ์•ˆํ•œ๊ฒƒ๋“ค์ด ์žˆ๋Š”์ง€ ํ™•์ธ๋จ.
        #๋น„๋ฐ€๋ฒˆํ˜ธ = ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ -> EqulaTo
    
        fcuser = Fcuser()  #models.py์— ์žˆ๋Š” Fcuser 
        fcuser.userid = form.data.get('userid')
        fcuser.username = form.data.get('username')
        fcuser.password = form.data.get('password')
            
        print(fcuser.userid,fcuser.password)  #ํšŒ์›๊ฐ€์ž… ์š”์ฒญ์‹œ ์ฝ˜์†”์ฐฝ์— ID๋งŒ ์ถœ๋ ฅ (ํ™•์ธ์šฉ, ๋”ฑํžˆ ํ•„์š”์—†์Œ)
        db.session.add(fcuser)  # id, name ๋ณ€์ˆ˜์— ๋„ฃ์€ ํšŒ์›์ •๋ณด DB์— ์ €์žฅ
        db.session.commit()  #์ปค๋ฐ‹
        
        return "๊ฐ€์ž… ์™„๋ฃŒ" #post์š”์ฒญ์ผ์‹œ๋Š” '/'์ฃผ์†Œ๋กœ ์ด๋™. (ํšŒ์›๊ฐ€์ž… ์™„๋ฃŒ์‹œ ํ™”๋ฉด์ด๋™)
            
    return render_template('register.html', form=form)
@app.route('/')
def hello():
    return render_template('hello.html')    # ์ด๋ฒˆ ํฌ์ŠคํŒ…์—๋Š” ํ•„์š”์—†์Œ(์ง€๋‚œํฌ์ŠคํŒ…๊บผ)

if __name__ == "__main__":
    basedir = os.path.abspath(os.path.dirname(__file__)) #dbํŒŒ์ผ์„ ์ ˆ๋Œ€๊ฒฝ๋กœ๋กœ ์ƒ์„ฑ
    dbfile = os.path.join(basedir, 'db.sqlite')#dbํŒŒ์ผ์„ ์ ˆ๋Œ€๊ฒฝ๋กœ๋กœ ์ƒ์„ฑ

    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + dbfile   
#sqlite๋ฅผ ์‚ฌ์šฉํ•จ. (๋งŒ์•ฝ mysql์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, id password ๋“ฑ... ๋” ํ•„์š”ํ•œ๊ฒŒ๋งŽ๋‹ค.)
    app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True 
#์‚ฌ์šฉ์ž ์š”์ฒญ์˜ ๋๋งˆ๋‹ค ์ปค๋ฐ‹(๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅ,์ˆ˜์ •,์‚ญ์ œ๋“ฑ์˜ ๋™์ž‘์„ ์Œ“์•„๋†จ๋˜ ๊ฒƒ๋“ค์˜ ์‹คํ–‰๋ช…๋ น)์„ ํ•œ๋‹ค.
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False 
#์ˆ˜์ •์‚ฌํ•ญ์— ๋Œ€ํ•œ track์„ ํ•˜์ง€ ์•Š๋Š”๋‹ค. True๋กœ ํ•œ๋‹ค๋ฉด warning ๋ฉ”์‹œ์ง€์œ ๋ฐœ
    app.config['SECRET_KEY'] = 'wcsfeufhwiquehfdx'

    csrf = CSRFProtect()
    csrf.init_app(app)

    db.init_app(app)
    db.app = app
    db.create_all()  #db ์ƒ์„ฑ


    
    app.run(host='127.0.0.1', port=5000, debug=True) 
     #ํฌํŠธ๋ฒˆํ˜ธ๋Š” ๊ธฐ๋ณธ 5000, ๊ฐœ๋ฐœ๋‹จ๊ณ„์—์„œ๋Š” debug๋Š” True

 

*forms.py

from flask_wtf import FlaskForm

from wtforms import StringField, 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('re_password')]) #equalTo("ํ•„๋“œ๋„ค์ž„")
    re_password = PasswordField('re_password', validators=[DataRequired()])


 

*register.html

 

<html>
    <head>
        <meta charset='utf-8'/>
        <meta name='viewport' content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
    
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
     integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
     integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous">
     </script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
     integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous">
     </script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
     integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous">
     </script>
    </head>

<body>
    <div class="container">
        <div class="row mt-5">
            <h1>ํšŒ์›๊ฐ€์ž…</h1>
        </div>
        <div class="row mt-5">
            <div class="col-12">
                <form method="POST" >   <!--์—‘์…˜ ์‚ญ์ œํ•ด์•ผ๋Œ--> 
                    {{form.csrf_token}}
                    <div class="form-group">
                        <!-- <label for="userid">์•„์ด๋””</label>
                        <input type="text" class="form-control" id="userid" placeholder="์•„์ด๋””" name="userid" /> -->
                        {{form.userid.label("์•„์ด๋””")}}
                        {{form.userid(class="form-control", placeholder="์•„์ด๋””")}}
                    </div>
                    <div class="form-group">
                        <!-- <label for="username">์ด๋ฆ„</label>
                        <input type="text" class="form-control" id="username" placeholder="์‚ฌ์šฉ์ž์ด๋ฆ„" name="username" /> -->
                        {{form.username.label("์‚ฌ์šฉ์ž ์ด๋ฆ„")}}
                        {{form.username(class="form-control", placeholder="์‚ฌ์šฉ์ž ์ด๋ฆ„")}}
                    </div>
                    <div class="form-group">
                        <!-- <label for="password">๋น„๋ฐ€๋ฒˆํ˜ธ</label>
                        <input type="password" class="form-control" id="password" placeholder="๋น„๋ฐ€๋ฒˆํ˜ธ" name="password" /> -->
                        {{form.password.label("๋น„๋ฐ€๋ฒˆํ˜ธ")}}
                        {{form.password(class="form-control", placeholder="๋น„๋ฐ€๋ฒˆํ˜ธ")}}
                    </div>
                    <div class="form-group">
                        <!-- <label for="re-password">๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ</label>
                        <input type="password" class="form-control" id="re_password" placeholder="๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ" name="re-password" /> -->
                        {{form.re_password.label("๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ")}}
                        {{form.re_password(class="form-control", placeholder="๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ")}}
                    </div>
                    <button type="submit" class="btn btn-primary">์ œ์ถœ</button>
                </form>
            </div>

        </div>
    </div>
</body>
</html>

 

์ง€๋‚œ ํฌ์ŠคํŒ…๊ณผ ๊ฒฐ๊ณผ๋ฌผ์˜ ๊ธฐ๋Šฅ๊ณผ ๋ชจ์–‘์€ ๊ฐ™์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋ ‡๊ฒŒ WTF๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋” ์ฝ”๋“œ๊ฐ€ ๊ฐ„๊ฒฐํ•ด์กŒ๊ณ , csrf_protect ๊ธฐ๋Šฅ๋„ ์ƒ๊ฒผ์Šต๋‹ˆ๋‹ค.

 

์ง€๋‚œํฌ์ŠคํŒ… : https://infinitt.tistory.com/30

 

ํ”Œ๋ผ์Šคํฌ (Flask) - ํšŒ์›๊ฐ€์ž… ๊ธฐ๋Šฅ ๋งŒ๋“ค๊ธฐ (MVC ํŒจํ„ด )

์›น์„ ๋””์ž์ธํ• ๋•Œ, ๊ธฐ๋ณธ์ ์ธ ๋””์ž์ธํŒจํ„ด์ค‘ ํ•˜๋‚˜์ธ MVC(Models views controller)๋ฅผ ์ด์šฉํ•ด์„œ ๊ฐ„๋‹จํ•œ ๊ธฐ๋Šฅ๊ตฌํ˜„์„ ํ•ด๋ณด๋ ค ๊ณ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์•ผ ์‚ฌํ›„์— ์œ ์ง€๋ณด์ˆ˜ ๋ฐ ์ˆ˜์ •์ด ํŽธ๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ( ์‚ฌ์‹ค ์ง€๊ธˆ ๊ตฌํ˜„ํ•˜๋ ค๋Š”..

infinitt.tistory.com

 

 

Contents

ํฌ์ŠคํŒ… ์ฃผ์†Œ๋ฅผ ๋ณต์‚ฌํ–ˆ์Šต๋‹ˆ๋‹ค

์ด ๊ธ€์ด ๋„์›€์ด ๋˜์—ˆ๋‹ค๋ฉด ๊ณต๊ฐ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.