You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Django与JWT实现移动端用户永久登录及Token自动刷新方案咨询

Hey there! Let's walk through how to implement this seamless auto-refresh functionality for your Django + JWT mobile app—this is a super common pattern and totally achievable with the right setup.

Core Approach: Use JWT Refresh Tokens

The key here is to split your JWT tokens into two types:

  • Access Token: Short-lived (you want 1 month here) for authenticating API requests
  • Refresh Token: Longer-lived, used to get a new Access Token (and a new Refresh Token) when the old one expires, without requiring the user to re-enter credentials.

We'll use djangorestframework-simplejwt—the most popular JWT package for Django—to handle the heavy lifting.

Step 1: Set Up Django + SimpleJWT

First, install the package and configure it in your project:

Install Dependencies

pip install djangorestframework-simplejwt django-redis

(We need django-redis for token blacklisting, which prevents old refresh tokens from being abused.)

Configure Settings.py

Add these settings to enable token rotation and blacklisting:

from datetime import timedelta

# ... rest of your settings

INSTALLED_APPS = [
    # ... existing apps
    'rest_framework',
    'rest_framework_simplejwt',
    'rest_framework_simplejwt.token_blacklist',  # For token blacklisting
]

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    )
}

SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(days=30),  # Your 1-month requirement
    'REFRESH_TOKEN_LIFETIME': timedelta(days=180),  # 6-month refresh token (adjust as needed)
    'ROTATE_REFRESH_TOKENS': True,  # Generate a new refresh token every time you refresh
    'BLACKLIST_AFTER_ROTATION': True,  # Mark old refresh tokens as invalid
    'ALGORITHM': 'HS256',
    'SIGNING_KEY': SECRET_KEY,
    'AUTH_HEADER_TYPES': ('Bearer',),
    # Configure Redis for blacklist storage
    'BLACKLIST_STORAGE': 'django_redis.cache.RedisCache',
    'BLACKLIST_STORAGE_OPTIONS': {
        'LOCATION': 'redis://127.0.0.1:6379/1',  # Update to your Redis instance
    },
}

Add URLs

Include the built-in token endpoints in your urls.py:

from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
)

urlpatterns = [
    # ... your existing URLs
    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]

These endpoints handle initial login (returning access/refresh tokens) and token refreshes.

Step 2: Frontend Auto-Refresh Logic

Your mobile app needs to manage the tokens and handle auto-refreshing. Here's how to approach it (example using React Native, but the logic applies to any mobile framework):

Store Tokens Securely

Never store tokens in plaintext! Use your platform's secure storage:

  • iOS: Keychain
  • Android: Keystore
  • Cross-platform: Libraries like react-native-keychain or expo-secure-store

Implement Auto-Refresh Logic

You have two strategies to choose from (or combine both):

1. Proactive Refresh (Recommended)

Check if the access token is about to expire, and refresh it before it does:

import jwtDecode from 'jwt-decode';
import * as SecureStore from 'expo-secure-store';

// Check if token is within 5 minutes of expiring
const isTokenExpiringSoon = (token) => {
  if (!token) return true;
  const decoded = jwtDecode(token);
  const currentTime = Date.now() / 1000;
  return decoded.exp - currentTime < 300; // 5 minutes in seconds
};

// Refresh tokens and update secure storage
const refreshTokens = async () => {
  const refreshToken = await SecureStore.getItemAsync('refreshToken');
  try {
    const response = await fetch('https://your-api-domain/api/token/refresh/', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ refresh: refreshToken }),
    });

    if (response.ok) {
      const { access, refresh } = await response.json();
      await SecureStore.setItemAsync('accessToken', access);
      await SecureStore.setItemAsync('refreshToken', refresh); // Save new refresh token
      return access;
    } else {
      // Refresh token expired—force user to log in
      await SecureStore.deleteItemAsync('accessToken');
      await SecureStore.deleteItemAsync('refreshToken');
      // Navigate to login screen
      navigation.navigate('Login');
      return null;
    }
  } catch (err) {
    console.error('Token refresh failed:', err);
    return null;
  }
};

// Wrapper for authenticated API calls
const fetchWithAuth = async (url, options = {}) => {
  let accessToken = await SecureStore.getItemAsync('accessToken');
  
  // Refresh if token is expiring soon
  if (isTokenExpiringSoon(accessToken)) {
    accessToken = await refreshTokens();
    if (!accessToken) return;
  }

  const authOptions = {
    ...options,
    headers: {
      ...options.headers,
      Authorization: `Bearer ${accessToken}`,
    },
  };

  return fetch(url, authOptions);
};

2. Reactive Refresh

If you miss the proactive window, handle the 401 Unauthorized response from your API by refreshing tokens and retrying the request:

// Modify fetchWithAuth to handle 401s
const fetchWithAuth = async (url, options = {}, retry = true) => {
  let accessToken = await SecureStore.getItemAsync('accessToken');
  const authOptions = {
    ...options,
    headers: {
      ...options.headers,
      Authorization: `Bearer ${accessToken}`,
    },
  };

  const response = await fetch(url, authOptions);
  
  // If we get a 401 and haven't retried yet
  if (response.status === 401 && retry) {
    const newAccessToken = await refreshTokens();
    if (newAccessToken) {
      // Retry the request with the new token
      return fetchWithAuth(url, options, false);
    }
  }

  return response;
};

Step 3: Security Best Practices

  • Refresh Token Rotation: By enabling ROTATE_REFRESH_TOKENS and BLACKLIST_AFTER_ROTATION, every refresh gives you a new refresh token, and the old one is invalidated. This limits damage if a token is stolen.
  • Secure Storage: Always use platform-native secure storage for tokens—never AsyncStorage or shared preferences.
  • Refresh Token Expiry: Don't set refresh tokens to never expire. A 6-month window is reasonable; if the user is active, tokens will keep rotating. If they're inactive for 6 months, they'll need to log in again (a good security balance).

内容的提问来源于stack exchange,提问作者Santhosh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:51:06