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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值