专栏首页sktjflask flask-login使用笔记(flask 55)

flask flask-login使用笔记(flask 55)

1,安装flask_login

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">pip install flask_login</pre>

2,在flask项目中配置flask_login

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">login_manager = LoginManager() app.config[‘SECRET_KEY‘]=‘234324234‘ #随意设置 login_manager.init_app(app)</pre>

3,设置session及其验证

1)提供user_loader的回调函数,主要是通过获取user对象存储到session中,自己实现最好启用缓存

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">@login_manager.user_loader def load_user(user_id): return User.get(user_id)</pre>

2)你的自定义的user类需要提供以下几个属性:

1.1 is_authenticated

属性,用来判断是否是已经授权了,如果通过授权就会返回true

1.2 is_active

属性,判断是否已经激活

1.3 is_anonymous

属性,判断是否是匿名用户

1.4 get_id()

方法,返回用户的唯一标识

这些属性和方法也可以直接继承于userMixin的默认方法和属性,不用自己去实现;

[

l

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">class User(UserMixin,db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True, nullable=False) email = db.Column(db.String(120), unique=True, nullable=False) password= db.Column(db.String(128)) avatar_hash = db.Column(db.String(32))

def __init__(self,id,username,email):
    self.id = id
    self.username = username
    self.email = email

def __repr__(self): return '<User %r>' % self.username</pre>

[

复制代码

](javascript:void(0); "复制代码")

4,登陆实操例子

4.1 登陆操作

[

复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">@app.route('/login', methods=['GET', 'POST']) def login(): # Here we use a class of some kind to represent and validate our # client-side form data. For example, WTForms is a library that will # handle this for us, and we use a custom LoginForm to validate. form = LoginForm() if form.validate_on_submit(): # Login and validate the user. # user should be an instance of your User class login_user(user)

    flask.flash('Logged in successfully.')

    next = flask.request.args.get('next')
    # is_safe_url should check if the url is safe for redirects.
    # See http://flask.pocoo.org/snippets/62/ for an example.
    if not is_safe_url(next): return flask.abort(400) return flask.redirect(next or flask.url_for('index')) return flask.render_template('login.html', form=form)</pre>

[

复制代码

](javascript:void(0); "复制代码")

这里的是登陆的请求操作,通过用户查询,判断是否有权限,然后通过login_user(user),其实也是调用user_loads()把用户设置到session中

这里的next参数可能有安全问题而不能直接跳转,可以考虑使用is_safe_url去过滤

4.2 登陆后的用户,默认提供了current_user的用户代理方法,可以在视图中直接使用:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">{% if current_user.is_authenticated %} Hi {{ current_user.name }}! {% endif %}</pre>

4.3 判断是否登陆,有权限要求,通过@login_required 来装饰

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">@app.route("/settings") @login_required def settings(): pass</pre>

4.4 退出登陆,这样会清除cookie和session

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">@app.route("/logout") @login_required def logout(): logout_user() return redirect(somewhere)</pre>

例子到此结束,接下来总结一些自定义的方法:

5,自定义登陆操作

5.1 未登陆的用户访问了@login_required视图的操作,可以设置一些默认的操作,否则可能直接报401的错误   1) 设置登陆视图,用于未授权操作的跳转:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">login_manager.login_view = “users.login”</pre>

2) 设置快闪消息,用于提示用户:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">login_manager.login_message = u"Bonvolu ensaluti por uzi tiun paĝon."</pre>

3) 设置未登录跳转可以携带消息的路径

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">login_manager.login_message_category = "info"</pre>

好像有点晦涩难懂,也就是在登陆页面的重定向时候,可以携带到登陆请求的参数,例如在一个用户页面,session过期,这是要跳转到登陆页面,那么会把当前的链接当参数存放到next里面传递到登陆请求中。当然了,这里还可以设置USE_SESSION_FOR_NEXT =True 这样就把链接放session里面了;而这些可携带参数链接必须在info的路径下。   4) 自己定义未登录的处理引擎

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">@login_manager.unauthorized_handler def unauthorized():

do stuff return a_response</pre>

6,定义客户端登陆 有时候你想要不使用cookies来登录用户,比如使用头部值或者作为查询参数传递的api键值。 在这些情况下,您应该使用request_loader回调。 这个回调应该和你的user_loader回调一样,只是它接受Flask请求而不是user_id。 举个例子,你可以通过路径的参数或者请求头里携带的Authorzation消息进行验证用户:

[

复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">@login_manager.request_loader def load_user_from_request(request):

# first, try to login using the api_key url arg   api_key = request.args.get('api_key')   if api_key:   user = User.query.filter_by(api_key=api_key).first()   if user:return user

next, try to login using Basic Auth

api_key = request.headers.get('Authorization')   if api_key:   api_key = api_key.replace('Basic ', '', 1)   try:   api_key = base64.b64decode(api_key)   except TypeError:   pass   user = User.query.filter_by(api_key=api_key).first()   if user:return user

finally, return None if both methods did not login the userreturn None</pre>

[

复制代码

](javascript:void(0); "复制代码")

7,匿名用户 默认是指没有登陆的用户,会设置一个AnonymousUserMixin对象到current_user里面,他有如下的属性和方法:   is_active and is_authenticated are False   is_anonymous is True   get_id() returns None 如果你的系统要求需要记住匿名用户的一些操作,你可以设置处理引擎(方法或者类),然后注册到login_manager:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">login_manager.anonymous_user = MyAnonymousUser</pre>

8,记住我操作 默认情况下,当用户关闭浏览器时,Flask会话被删除,用户注销。 “记住我”可以防止用户在关闭浏览器时意外退出。这并不意味着在用户注销后记住或预先填写登录表单中的用户名或密码。

“记住我”功能可能会很难实现。但是,Flask-Login使它几乎是透明的 - 只需将remember = True传递给login_user调用即可。 Cookie将被保存在用户的计算机上,然后如果不在会话中,Flask-Login将自动从该Cookie恢复用户ID。 cookie到期前的时间可以通过REMEMBER_COOKIE_DURATION配置进行设置,也可以通过login_user进行设置。 cookie是防篡改的,所以如果用户篡改它(即插入别人的用户ID代替他们自己的),cookie将仅仅被拒绝,就好像它不在那里一样。

这一级别的功能是自动处理的。但是,如果您的应用程序处理任何类型的敏感数据,您可以(也应该可以)提供额外的基础结构来提高记忆Cookie的安全性。

9,可选的令牌token 使用令牌token来代替存放用户信息到session里面,这样具有更多的灵活性:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">@login_manager.user_loader def load_user(session_token): return User.query.filter_by(session_token=session_token).first()</pre>

如果使用token来验证,则你必须改user类的get_id方法:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">def get_id(self): return unicode(self.session_token)</pre>

这样,当用户更改密码时,您可以自由地将用户的会话标记更改为新的随机生成的值,这将确保其旧认证会话将不再有效。 请注意,会话令牌仍然必须唯一标识用户,可将其视为第二个用户标识。

10,刷新登陆 适用某些特殊的场景吧!例如你修改了用户的密码或者个人信息之后,是不是很多平台都会要求你重新登陆,这里就设计session的清除然后重新加载等的问题。 刷新登陆也不难,跟设置未授权的跳转是差不多的: ** 10.1 配置参数**

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">login_manager.refresh_view = "accounts.reauthenticate" login_manager.needs_refresh_message = ( u"To protect your account, please reauthenticate to access this page." ) login_manager.needs_refresh_message_category = "info"</pre>

也是配置刷新后跳转的视图,提示信息,可传递参数路径 ** 10.2 自定义处理引擎:**

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">@login_manager.needs_refresh_handler def refresh():   # do stuffreturn a_response</pre>

然后再需要刷新的方法里调用confirm_login()函数,具体可查看API 10.3 cookie 的细节可以在应用设置中定义。   REMEMBER_COOKIE_NAME 存储“记住我”信息的 cookie 名。 默认值: remember_token   REMEMBER_COOKIE_DURATION cookie 过期时间,为一个 datetime.timedelta 对象。 默认值: 365 天 (1 非闰阳历年)   REMEMBER_COOKIE_DOMAIN 如果“记住我” cookie 应跨域,在此处设置域名值 (即 .example.com 会允许 example 下所有子域 名)。 默认值: None   REMEMBER_COOKIE_PATH 限制”记住我“ cookie 存储到某一路径下。 默认值: /   REMEMBER_COOKIE_SECURE 限制 “Remember Me” cookie 在某些安全通道下有用 (典型地 HTTPS)。默认值: None   REMEMBER_COOKIE_HTTPONLY 保护 “Remember Me” cookie 不能通过客户端脚本访问。 默认值: False

11 会话保护 当上述特性保护“记住我”令牌免遭 cookie 窃取时,会话 cookie 仍然是脆弱的。 Flask-Login 包含了会话保护来帮助阻止用户会话被盗用。

你可以在 LoginManager 上和应用配置中配置会话保护。如果它被启用,它可以在 basic 或 strong 两种模式中运行。要在 LoginManager 上设置它,设置 session_protection 属性为 "basic" 或 "strong":

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">login_manager.session_protection = "strong"</pre>

或者,禁用它:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">login_manager.session_protection = None</pre>

默认,它被激活为 "basic" 模式。它可以在应用配置中设定 SESSION_PROTECTION 为 None 、 "basic" 或 "strong" 来禁用。

当启用了会话保护,每个请求,它生成一个用户电脑的标识(基本上是 IP 地址和 User Agent 的 MD5 hash 值)。如果会话不包含相关的标识,则存储生成的。如果存在标识,则匹配生成的,之后请求可用。

在 basic 模式下或会话是永久的,如果该标识未匹配,会话会简单地被标记为非活 跃的,且任何需要活跃登入的东西会强制用户重新验证。(当然,你必须已经使用了活跃登入机制才能奏效。)

在 strong 模式下的非永久会话,如果该标识未匹配,整个会话(记住的令牌如果存在,则同样)被删除。

12 本地化 默认情况下,当用户需要登录,LoginManager 使用 flash 来显示信息。这些信息都是英文的。如果你需要本地化,设置 LoginManager 的 localize_callback 属性为一个函数,该函数在消息被发送到 flash 的时候被调用,比如,gettext。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Docker 日志切割参考

    ===============================================

    用户5760343
  • python之crawlspider初探

    <pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: bre...

    用户5760343
  • bootstrap 左边栏菜单 常用样式

    <style> /* Custom Styles / ul.nav-tabs{ width: 140px; margin-top: 20px; ...

    用户5760343
  • 【DMP篇】15个DMP相关经典问题集锦

    Q1:宋老师您好,我目前在互联网公司负责营销中心DMP的搭建工作,想向您请教几个问题:

    iCDO互联网数据官
  • android抓屏

    现在无论是应用,还是游戏中,都经常会有分享的功能。分享,不仅要分享文字,也要分享应用或者游戏的屏幕截图,这样才能做到图文并茂,吸引到更多的用户。 想要做图片的分...

    xiangzhihong
  • 大数据24小时 | 腾讯将用大数据构建互联网+医疗连接器 奥美健康想做运动大数据领域的“BAT”

    腾讯启动“疼爱医疗”战略 用大数据构建互联网+医疗连接器 ? 近日,腾讯公司副总裁丁珂在“互联网+慢病管理”发布会上宣布正式启动“腾爱医疗”战略,将利用腾讯...

    数据猿
  • Spring依赖注入@Autowired深层原理、源码级分析,感受DI带来的编程之美【享学Spring】

    关于Spring IOC的依赖注入(DI机制),之前虽有过分析,但总感觉一直落了一块:对@Autowired注解元数据的解析部分。

    YourBatman
  • 超30亿投资+和“国内BAT之外仅剩的巨头”合作,暴风科技打的什么牌?

    镁客网
  • 一个非典型Spring循环依赖的问题分析

    这两天工作遇到了一个挺有意思的Spring循环依赖的问题,但是这个和以往遇到的循环依赖问题都不太一样,隐藏的相当隐蔽,网络上也很少看到有其他人遇到类似的问题。这...

    猿天地
  • 12 个UX设计师典型面试问题 · 助你通过面试

    这里有几个典型的UX设计师面试问题,如果你想成功通过你的面试,建议你仔细阅读并做好事前准备。

    宇相

扫码关注云+社区

领取腾讯云代金券