美文网首页
Flask实战1-用户认证

Flask实战1-用户认证

作者: 猴子精h | 来源:发表于2017-09-27 00:39 被阅读75次

写在前面:此时实战的项目参考<<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'))
    

相关文章

网友评论

      本文标题:Flask实战1-用户认证

      本文链接:https://www.haomeiwen.com/subject/duhyextx.html