Flutter & Django : Как аутентифицировать пользователя по JWT?

Я разрабатываю страницы аутентификации для своего приложения, используя Flutter для мобильного фронтенда и Django для бэкенда.

Функциональность входа в систему работает отлично, но я столкнулся с проблемой при выходе из системы. Когда я пытаюсь выйти из системы, возвращается ошибка «forbidden», указывающая на то, что пользователь не прошел аутентификацию.

Я подозреваю, что проблема может быть связана с тем, как я устанавливаю jwt в заголовках HTTP-запросов во Flutter.

Может кто-нибудь взглянуть и помочь мне устранить неполадки?

Спасибо!

Flutter

class AuthService {
  // Base URL for the user endpoints
  final String _loginUrl = '$BASE_URL/users/login';
  final String _isLoggedInUrl = '$BASE_URL/users/is_logged_in';
  final String _logoutUrl = '$BASE_URL/users/logout';

  Future<String?> login(String email, String password) async {
    final response = await http.post(
      Uri.parse(_loginUrl),
      headers: {'Content-Type': 'application/json'},
      body: json.encode({'email': email, 'password': password}),
    );

    if (response.statusCode == 200) {
      // Store the JWT token in shared preferences
      final prefs = await SharedPreferences.getInstance();
      final token = json.decode(response.body)['jwt'];
      await prefs.setString('jwt', token);
      return token;
    } else {
      throw Exception('Failed to login');
    }
  }

  Future<bool> isLoggedIn() async {
    print("In isLoggedIn");
    final prefs = await SharedPreferences.getInstance();
    final token = prefs.getString('jwt');

    // If token is null, the user is not logged in
    if (token == null) {
      return false;
    }

    final response = await http.post(
      Uri.parse(_isLoggedInUrl),
      headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'Authorization': 'Bearer $token',
      },
    );

    // Check response status and print for debugging
    if (response.statusCode == 200) {
      final sth = json.decode(response.body);
      print(sth);
      return true; // User is logged in if the response is successful
    } else {
      return false; // User is not logged in if the response fails
    }
  }

  Future<void> logout() async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.remove('jwt'); // Remove JWT from shared preferences

    // Optionally call the logout API
    final token = prefs.getString('jwt'); // Get the token for logout request
    await http.post(
      Uri.parse(_logoutUrl),
      headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer $token', // Include token if required
      },
    );
  }
}

Django

Сообщение об ошибке

User logged in successfully and JWT token set in cookie
[28/Oct/2024 13:48:24] "POST /users/login HTTP/1.1" 200 166
Forbidden: /users/logout
[28/Oct/2024 13:48:39] "POST /users/logout HTTP/1.1" 403 29

В операции выхода из системы (на стороне Flutter) вы удаляете JWT прямо перед тем, как пытаетесь прочитать его в запросе к /logout.

    await prefs.remove('jwt'); // <-- Delete JWT

    // Optionally call the logout API
    final token = prefs.getString('jwt'); // <-- Attempt to retrieve JWT

Поскольку JWT был удален, token становится null. Что, в свою очередь, означает, что JWT-заголовок запроса, идущего к Django, не содержит действительного токена носителя, и это вызывает HTTP 403.

Проверить можно, закомментировав строку, удаляющую JWT на стороне клиента, или записав значение заголовка JWT в запросе, который заканчивается на /logout.

Вернуться на верх