python flask 如何在一个服务端登录,另一个应用也可以保持登录状态

问题描述:
在一个flask应用程序上设计登录界面,登录后,另一个flask应用可以获取当前的登录状态。
问题解决思路:
session的共享,首先将登录的session存储到redis中,然后另外一个flask获取当前的session状态,通过user_id来判断当前的登录状态。login_user()函数会将user_id存入,logout_user()会将用户的user_id进行弹出。以下为login_user logout_user的源码:

def login_user(user, remember=False, force=False, fresh=True):
‘’’
Logs a user in. You should pass the actual user object to this. If the
user’s is_active property is False, they will not be logged in
unless force is True.

This will return ``True`` if the log in attempt succeeds, and ``False`` if
it fails (i.e. because the user is inactive).

:param user: The user object to log in.
:type user: object
:param remember: Whether to remember the user after their session expires.
    Defaults to ``False``.
:type remember: bool
:param force: If the user is inactive, setting this to ``True`` will log
    them in regardless. Defaults to ``False``.
:type force: bool
:param fresh: setting this to ``False`` will log in the user with a session
    marked as not "fresh". Defaults to ``True``.
:type fresh: bool
'''
if not force and not user.is_active:
    return False

user_id = getattr(user, current_app.login_manager.id_attribute)()
session['user_id'] = user_id
session['_fresh'] = fresh
session['_id'] = _create_identifier()

if remember:
    session['remember'] = 'set'

_request_ctx_stack.top.user = user
user_logged_in.send(current_app._get_current_object(), user=_get_user())
return True

def logout_user():
‘’’
Logs a user out. (You do not need to pass the actual user.) This will
also clean up the remember me cookie if it exists.
‘’’

user = _get_user()

if 'user_id' in session:
    session.pop('user_id')

if '_fresh' in session:
    session.pop('_fresh')

cookie_name = current_app.config.get('REMEMBER_COOKIE_NAME', COOKIE_NAME)
if cookie_name in request.cookies:
    session['remember'] = 'clear'

user_logged_out.send(current_app._get_current_object(), user=user)

current_app.login_manager.reload_user()
return True

代码实现:
首先,应用1的配置:用的是MySQL数据库

DATABASE_URL=‘mysql+pymysql://root:root@127.0.0.1/flask’

	SECRET_KEY = os.environ.get('SECRET_KEY') or 'you-will-never-guess'
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
        'sqlite:///' + os.path.join(basedir, 'app.db')
    REDIS_URL=os.environ.get('REDIS_URL') or 'redis://'

    SESSION_TYPE=os.environ.get('SESSION_TYPE') or 'redis'
    SESSION_PERMANENT=os.environ.get('SESSION_PERMANENT') or False
    SESSION_USE_SIGNER=os.environ.get('SESSION_USE_SIGNER') or False
    SESSION_KEY_PREFIX=os.environ.get('SESSION_KEY_PREFIX') or 'session:'
    REDIS_HOST=os.environ.get('REDIS_HOST') or '127.0.0.1'
    REDIS_PORT=os.environ.get('REDIS_PORT') or '6379'
    REDIS_PASSWORD=os.environ.get('REDIS_PASSWORD') or ''
    SESSION_REDIS=redis.Redis(host=REDIS_HOST, port=REDIS_PORT, password=REDIS_PASSWORD) 
    PERMANENT_SESSION_LIFETIME= datetime.timedelta(seconds=30*60) 

ying在这里插入图片描述

应用2的配置:

SESSION_TYPE=os.environ.get('SESSION_TYPE') or 'redis'
SESSION_PERMANENT=os.environ.get('SESSION_PERMANENT') or False
SESSION_USE_SIGNER=os.environ.get('SESSION_USE_SIGNER') or False
SESSION_KEY_PREFIX=os.environ.get('SESSION_KEY_PREFIX') or 'session:'
REDIS_HOST=os.environ.get('REDIS_HOST') or '127.0.0.1'
REDIS_PORT=os.environ.get('REDIS_PORT') or '6379'
REDIS_PASSWORD=os.environ.get('REDIS_PASSWORD') or ''
SESSION_REDIS=redis.Redis(host=REDIS_HOST, port=REDIS_PORT, password=REDIS_PASSWORD) 
PERMANENT_SESSION_LIFETIME= datetime.timedelta(seconds=30*60) 

在这里插入图片描述

然后可以自己写一个判断登录状态的装饰器代替login_required

def is_login(func):

    @functools.wraps(func)

    def inner(*args,**kwargs):

        user = session.get('user_id')

        if not user:

            return redirect('login')

        return func(*args,**kwargs)

    return inner

在这里插入图片描述

方法二是依然利用login_required 但是将load_user 函数更改一下。

在这里插入图片描述

返回值必须是一个object的user且带属性is_authenticated ,否则在login_required中会出现错误

def login_required(func):
    '''
    If you decorate a view with this, it will ensure that the current user is
    logged in and authenticated before calling the actual view. (If they are
    not, it calls the :attr:`LoginManager.unauthorized` callback.) For
    example::

        @app.route('/post')
        @login_required
        def post():
            pass

    If there are only certain times you need to require that your user is
    logged in, you can do so with::

        if not current_user.is_authenticated:
            return current_app.login_manager.unauthorized()

    ...which is essentially the code that this function adds to your views.

    It can be convenient to globally turn off authentication when unit testing.
    To enable this, if the application configuration variable `LOGIN_DISABLED`
    is set to `True`, this decorator will be ignored.

    .. Note ::

        Per `W3 guidelines for CORS preflight requests
        <http://www.w3.org/TR/cors/#cross-origin-request-with-preflight-0>`_,
        HTTP ``OPTIONS`` requests are exempt from login checks.

    :param func: The view function to decorate.
    :type func: function
    '''
    @wraps(func)
    def decorated_view(*args, **kwargs):
        if request.method in EXEMPT_METHODS:
            return func(*args, **kwargs)
        elif current_app.login_manager._login_disabled:
            return func(*args, **kwargs)
        **elif not current_user.is_authenticated:**
            return current_app.login_manager.unauthorized()
        return func(*args, **kwargs)
    return decorated_view

总体大概应该就是这样了。

参考文章
https://www.py.cn/kuangjia/flask/11390.html

原文地址:https://blog.csdn.net/lsyhaoshuai/article/details/110528498

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Jinja2:是Python的Web项目中被广泛应用的模板引擎,是由Python实现的模板语言,Jinja2 的作者也是 Flask 的作者。他的设计思想来源于Django的模板引擎,并扩展了其语法和一系列强大的功能,其是Flask内置的模板语言。
Fullcalendar日历使用,包括视图选择、事件插入、编辑事件、事件状态更改、事件添加和删除、事件拖动调整,自定义头部,加入el-popover显示图片、图片预览、添加附件链接等,支持手机显示。
监听QQ消息并不需要我们写代码,因为市面上已经有很多开源QQ机器人框架,在这里我们使用go-cqhttp官方文档:go-cqhttp如果您感兴趣的话,可以阅读一下官方文档,如果不想看,直接看我的文章即可。
【Flask框架】—— 视图和URL总结
python+web+flask轻量级框架的实战小项目。登录功能,后续功能可自行丰富。
有了这个就可以配置可信IP,关键是不需要企业认证,个人信息就可以做。
本专栏是对Flask官方文档中个人博客搭建进行的归纳总结,与官方文档结合事半功倍。 本人经验,学习一门语言或框架时,请首先阅读官方文档。学习完毕后,再看其他相关文章(如本系列文章),才是正确的学习道路。
本专栏是对Flask官方文档中个人博客搭建进行的归纳总结,与官方文档结合事半功倍。基础薄弱的同学请戳Flask官方文档教程 本人经验,学习一门语言或框架时,请首先阅读官方文档。学习完毕后,再看其他相关文章(如本系列文章),才是正确的学习道路。 如果python都完全不熟悉,一定不要着急学习框架,请首先学习python官方文档,一步一个脚印。要不然从入门到放弃是大概率事件。 Python 官方文档教程
快到年末了 相信大家都在忙着处理年末数据 刚好有一个是对超市的商品库存进行分析的学员案例 真的非常简单~
一个简易的问答系统就这样完成了,当然,这个项目还可以进一步完善,比如 将数据存入Elasticsearch,通过它先进行初步的检索,然后再通过这个系统,当然我们也可以用其他的架构实现。如果你对这系统还有其他的疑问,也可以再下面进行留言!!!
#模版继承和页面之间的调用@app.route(&quot;/bl&quot;)def bl(): return render_template(&quot;file_2.html&quot;)主ht
#form表达提交@app.route(&quot;/data&quot;,methods=[&#39;GET&#39;,&#39;POST&#39;]) #methods 让当前路由支持GET 和
#form表达提交@app.route(&quot;/data&quot;,methods=[&#39;GET&#39;,&#39;POST&#39;]) #methods 让当前路由支持GET 和
#session 使用app.secret_key = &quot;dsada12212132dsad1232113&quot;app.config[&#39;PERMANENT_SESSION_LI
#文件上传@app.route(&quot;/file&quot;,methods=[&#39;GET&#39;,&#39;POST&#39;])def file(): if request.meth
#跳转操作:redirect@app.route(&quot;/red&quot;)def red(): return redirect(&quot;/login&quot;)
#session 使用app.secret_key = &quot;dsada12212132dsad1232113&quot;app.config[&#39;PERMANENT_SESSION_LI
@app.route(&quot;/req&quot;,methods=[&#39;GET&#39;,&#39;POST&#39;])def req(): print(request.headers)
#模版继承和页面之间的调用@app.route(&quot;/bl&quot;)def bl(): return render_template(&quot;file_2.html&quot;)主ht
#文件操作:send_file,支持图片 视频 mp3 文本等@app.route(&quot;/img&quot;)def img(): return send_file(&quot;1.jpg&q