MST

星途 面试题库

面试题:Python装饰器在身份验证场景下的优化

假设你正在开发一个Web应用,需要对某些视图函数进行身份验证。现有一个简单的装饰器用于验证用户登录状态,但每次验证都查询数据库,效率较低。请优化这个装饰器,通过缓存等机制提高验证效率,简述优化思路并给出代码实现。
22.0万 热度难度
编程语言Python

知识考点

AI 面试

面试题答案

一键面试

优化思路

  1. 使用缓存来存储用户的登录状态,这样在验证时可以先从缓存中获取,避免每次都查询数据库。
  2. 可以选择合适的缓存工具,比如Python中的functools.lru_cache(适用于简单场景,基于内存缓存),或者使用更专业的缓存工具如Redis(适用于分布式场景,更强大灵活)。这里以functools.lru_cache为例进行说明。

代码实现

import functools
from flask import session

# 模拟数据库查询函数
def check_user_login_in_db(user_id):
    # 实际这里应该是查询数据库的逻辑
    return True if user_id in [1, 2, 3] else False

# 优化后的装饰器
def login_required(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        user_id = session.get('user_id')
        if not user_id:
            return '请先登录', 401
        # 使用lru_cache缓存结果
        @functools.lru_cache(maxsize=128)
        def cached_check_user_login(user_id):
            return check_user_login_in_db(user_id)
        if cached_check_user_login(user_id):
            return func(*args, **kwargs)
        else:
            return '权限不足', 403
    return wrapper

假设这是一个Flask应用中的装饰器,session用于存储用户会话信息。check_user_login_in_db模拟数据库查询判断用户是否登录。login_required装饰器通过lru_cache缓存了数据库查询结果,提高验证效率。

如果使用Redis作为缓存:

import redis
from flask import session

r = redis.Redis(host='localhost', port=6379, db=0)

# 模拟数据库查询函数
def check_user_login_in_db(user_id):
    # 实际这里应该是查询数据库的逻辑
    return True if user_id in [1, 2, 3] else False

# 优化后的装饰器
def login_required(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        user_id = session.get('user_id')
        if not user_id:
            return '请先登录', 401
        cache_key = f'user:{user_id}:is_login'
        is_login = r.get(cache_key)
        if is_login:
            if is_login.decode('utf-8') == 'True':
                return func(*args, **kwargs)
            else:
                return '权限不足', 403
        else:
            is_login = check_user_login_in_db(user_id)
            r.set(cache_key, str(is_login))
            if is_login:
                return func(*args, **kwargs)
            else:
                return '权限不足', 403
    return wrapper

这里使用Redis作为缓存,通过r.getr.set操作缓存,将用户登录状态存储在Redis中,提高验证效率。