Flask实战1-用户认证

写在前面:此时实战的项目参考<<Flask Web开发>>一书项目示例

Flask Web.jpg

使用的模块

  • Flask-Login:管理已登入用户的会话
  • Werkzeug: 生成密码hash值并校验
  • itsdangerous:生成并核对激活用户链接
  1. 为提高密码的安全性,数据库中存储密码的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方法验证用户输入的密码是否与数据库中的密码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()
    
    
        # 表单类还有两个自定义的验证函数,以方法的实行实现。如果表单类中定义了以validate_开头且后面跟着字段名的方法,
        # 这个方法就和验证函数一起调用
    
        # 保证了注册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发送一个默认邮件,用户需要点击认证之后才能登入;实现方式很简单,确认邮件中添加链接http://your_domain/auth/confirm/<id>, 这个id是用户表的主键,视图函数接收到这个主键并把用户状态更新;

    为了安全,使用itsdangerous生成用户id的安全令牌;

    # 用户类中添加方法
    
    class User(UserMixin, db.Model):
    
        ...
        
        # 根据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
    

    当没有验证的用户访问页面时,需要将他们重定向到一个统一的页面,

    Flask提供了4个请求钩子:
    - before_first_request:注册一个函数,在处理第一个请求之前运行。
    - before_request:注册一个函数,在每次请求之前运行。
    - after_request:注册一个函数,如果没有未处理的异常抛出,在每次请求之后运行。
    - teardown_request:注册一个函数,即使有未处理的异常抛出,也在每次请求之后运行。
    
    在请求钩子函数和视图函数之间共享数据一般使用上下文全局变量 g。例如,before_ request 处理程序可以从数据库中加载已登录用户,并将其保存到 g.user 中。随后调用视 图函数时,视图函数再使用 g.user 获取用户。
    

    这里可以使用before_request来实现, 对于蓝本来说,before_request钩子只能应用到属于蓝本的请求上,若想对全集请求生效,还需要使用before_app_request装饰器:

    # 验证用户是否已经通过邮件确认
    @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'))
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,165评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,720评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,849评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,245评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,596评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,747评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,977评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,708评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,448评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,657评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,141评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,493评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,153评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,890评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,799评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,685评论 2 272

推荐阅读更多精彩内容