Flask實戰(zhàn)1-用戶認證

寫在前面:此時實戰(zhàn)的項目參考<<Flask Web開發(fā)>>一書項目示例

Flask Web.jpg

使用的模塊

  • Flask-Login:管理已登入用戶的會話
  • Werkzeug: 生成密碼hash值并校驗
  • itsdangerous:生成并核對激活用戶鏈接
  1. 為提高密碼的安全性,數(shù)據(jù)庫中存儲密碼的hash值

    from werkzeug.security import generate_password_hash, check_password_hash
    
    class User(db.Model):
        # ...
        password_hash = db.Column(db.String(128))
        
    
        @property
        def password(self):
            raise AttributeError('password is not a readable attribute')
    
        @password.setter
        def password(self, password):
            self.password_hash = generate_password_hash(password)
            
        # 利用verify_password方法驗證用戶輸入的密碼是否與數(shù)據(jù)庫中的密碼hash值一致 
        def verify_password(self, password):
            return check_password_hash(self.password_hash, password)
    
  2. 用戶登入使用Flask-Login模塊,詳情請見另一篇博客;

  3. 注冊用戶

    注冊用戶使用Flask-WTF表單, 其中可以很方便地使用WTF表單字段的驗證功能:

    class RegistrationForm(Form):
        email = StringField(
            'Email', validators=[
                DataRequired(), Length(
                    1, 64), Email()])
        username = StringField(
            'Username',
            validators=[
                DataRequired(),
                Length(
                    1,
                    64),
                Regexp(
                    '^[A-Za-z0-9_.]*$',
                    0,
                    'Username must have only letters, numbers, dots or underscores')])
        password = StringField(
            'Password',
            validators=[
                DataRequired(),
                EqualTo(
                    'password2',
                    message='Passwords must match.')])
        password2 = PasswordField('Confirm password', validators=[DataRequired()])
        submit = SubmitField()
    
    
        # 表單類還有兩個自定義的驗證函數(shù),以方法的實行實現(xiàn)。如果表單類中定義了以validate_開頭且后面跟著字段名的方法,
        # 這個方法就和驗證函數(shù)一起調(diào)用
    
        # 保證了注冊email的唯一
        def validate_email(self, field):
            if User.query.filter_by(email=field.data).first():
                raise ValidationError("Email already registered.")
    
        # 保證了注冊username唯一
        def validate_username(self, field):
            if User.query.filter_by(username=field.data).first():
                raise ValidationError("Username already use.")
    
  4. 確認賬戶

    很多使用用戶注冊成功后,會像用戶的email發(fā)送一個默認郵件,用戶需要點擊認證之后才能登入;實現(xiàn)方式很簡單,確認郵件中添加鏈接http://your_domain/auth/confirm/<id>, 這個id是用戶表的主鍵,視圖函數(shù)接收到這個主鍵并把用戶狀態(tài)更新;

    為了安全,使用itsdangerous生成用戶id的安全令牌;

    # 用戶類中添加方法
    
    class User(UserMixin, db.Model):
    
        ...
        
        # 根據(jù)id, 生成token
        def generate_confirmation_token(self, expiration=3600):
            s = Serializer(current_app.config['SECRET_KEY'], expiration)
            return s.dumps({'confirm': self.id})
    
        # 驗證token是否與id一致,一致則更新user對象的屬性
        def confirm(self, token):
            s = Serializer(current_app.config['SECRET_KEY'])
            try:
                data = s.loads(token)
            except:
                return False
            if data.get('confirm') != self.id:
                return False
            self.confirmed = True
            db.session.add(self)
            return True
    

    當沒有驗證的用戶訪問頁面時,需要將他們重定向到一個統(tǒng)一的頁面,

    Flask提供了4個請求鉤子:
    - before_first_request:注冊一個函數(shù),在處理第一個請求之前運行。
    - before_request:注冊一個函數(shù),在每次請求之前運行。
    - after_request:注冊一個函數(shù),如果沒有未處理的異常拋出,在每次請求之后運行。
    - teardown_request:注冊一個函數(shù),即使有未處理的異常拋出,也在每次請求之后運行。
    
    在請求鉤子函數(shù)和視圖函數(shù)之間共享數(shù)據(jù)一般使用上下文全局變量 g。例如,before_ request 處理程序可以從數(shù)據(jù)庫中加載已登錄用戶,并將其保存到 g.user 中。隨后調(diào)用視 圖函數(shù)時,視圖函數(shù)再使用 g.user 獲取用戶。
    

    這里可以使用before_request來實現(xiàn), 對于藍本來說,before_request鉤子只能應用到屬于藍本的請求上,若想對全集請求生效,還需要使用before_app_request裝飾器:

    # 驗證用戶是否已經(jīng)通過郵件確認
    @auth.before_app_request
    def before_request():
        if current_user.is_authenticated:
            current_user.ping()
            if not current_user.confirmed \
            and request.endpoint \
            and request.endpoint[:5] != 'auth.' \
            and request.endpoint != 'static':
                return redirect(url_for('auth.unconfirmed'))
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,500評論 19 139
  • 22年12月更新:個人網(wǎng)站關(guān)停,如果仍舊對舊教程有興趣參考 Github 的markdown內(nèi)容[https://...
    tangyefei閱讀 35,388評論 22 257
  • 經(jīng)過對django的初步學習,我們已經(jīng)對后臺的基本流程以及django的運作有了一定的了解,但是這還不足夠,dja...
    coder_ben閱讀 3,953評論 8 34
  • 效果圖 這一章節(jié)完成后的效果如下: 1.普通用戶 2.管理者 Github鏈接 https://github.co...
    happyte閱讀 2,390評論 0 2
  • 第二部分 Blog例子 第八章 用戶驗證 大部分程序需要追蹤用戶身份。當用戶連接到程序,通過一系列步驟使自己的身份...
    易木成華閱讀 1,406評論 0 4

友情鏈接更多精彩內(nèi)容