gunicorn多线程部署django导致的登陆错误

发布于:2025-06-01 ⋅ 阅读:(30) ⋅ 点赞:(0)

使用django写后端,认证系统使用了内存中的令牌存储(authentication.py中的user_tokens字典)。

from secrets import token_hex
from .models import User

# Create a custom token generation function
def generate_token():
    return token_hex(20)  # Generate a 40-character hex token

# Create an in-memory token storage (for demonstration)
# In production, you would use a database model for this
user_tokens = {}  # user_id: token

# Custom authentication for DRF views
class CustomTokenAuthentication:
    def authenticate(self, request):
        auth_header = request.headers.get('Authorization')
        if not auth_header or not auth_header.startswith('Token '):
            return None
            
        token = auth_header.split(' ')[1]
        
        # Find user with this token
        for user_id, user_token in user_tokens.items():
            if user_token == token:
                try:
                    user = User.objects.get(id=user_id)
                    return (user, token)
                except User.DoesNotExist:
                    return None
                    
        return None
        
    def authenticate_header(self, request):
        return 'Token' 

当使用Gunicorn并配置多个工作进程时(workers = multiprocessing.cpu_count() * 2 + 1),每个工作进程都拥有独立的内存空间和自己的user_tokens字典副本。

这就导致:
用户登录时,其令牌仅存储在某个工作进程的内存中。
而后续请求可能会被路由到另一个没有该令牌内存记录的工作进程。
这将导致认证失败,从而触发前端api.js中的拦截器清除localStorage中的令牌。 

import axios from 'axios'

// 创建一个axios实例
const apiClient = axios.create({
  baseURL: '/api',
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json'
  },
  // 添加超时设置,避免请求挂起过长时间
  timeout: 10000
})

// 请求拦截器 - 添加认证token
apiClient.interceptors.request.use(
  config => {
    // 每次请求时重新从localStorage获取token,确保使用最新token
    const token = localStorage.getItem('upload_token')
    if (token) {
      config.headers.Authorization = `Token ${token}`
    }
    
    return config
  },
  error => {
    return Promise.reject(error)
  }
)

// 响应拦截器 - 全局错误处理
apiClient.interceptors.response.use(
  response => {
    return response
  },
  error => {
    console.log('API请求错误:', error.response)
    
    // 处理401未授权错误
    if (error.response && error.response.status === 401) {
      // 可以在这里处理自动登出逻辑
      console.log('认证失败,清除令牌')
      localStorage.removeItem('upload_token')
      localStorage.removeItem('upload_user')
      window.location.href = '/login'
    }
    
    return Promise.reject(error)
  }
)

// 简化的API请求方法
const optimizedApiClient = {
  get: (url, config = {}) => apiClient.get(url, config),
  post: (url, data, config = {}) => apiClient.post(url, data, config),
  put: (url, data, config = {}) => apiClient.put(url, data, config),
  delete: (url, config = {}) => apiClient.delete(url, config)
}

export default optimizedApiClient 

导致用户登录-》进入其他页面-》重导到登录页反复横跳

处理:

临时处理:

        将gunicorn改成单线程

长期处理:

        建立token存储表单,采用持久化令牌存储方案:将令牌存入数据库表中,而非内存字典
确保所有工作进程都能访问同一份令牌数据


网站公告

今日签到

点亮在社区的每一天
去签到