Flutter with djangorestframework backend how to keep user logged in after changing view

17 Views Asked by At

After a successful user login (MySQL) , the user gets forwarded to a Mainpage and am working to implement a user profile screen. but if i call the UserView to get the user's username and email i receive a

Forbidden: /accounts/user
HTTP GET /accounts/user 403 [0.01, 192.168.1.2:42536

However doing the same request in browser works: Working browser call here are the relevant views:

class UserRegister(APIView):
    permission_classes = (permissions.AllowAny,)
    def post(self, request):
        clean_data = custom_validation(request.data)
        serializer = UserRegisterSerializer(data=clean_data)
        if serializer.is_valid(raise_exception=True):
            user = serializer.create(clean_data)
            if user:
                return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(clean_data,status=status.HTTP_400_BAD_REQUEST)


class UserLogin(APIView):
    permission_classes = (permissions.AllowAny,)
    authentication_classes = (SessionAuthentication,)
    ##
    def post(self, request):
        data = request.data
        assert validate_email(data)
        assert validate_password(data)
        serializer = UserLoginSerializer(data=data)
        if serializer.is_valid(raise_exception=True):
            user = serializer.check_user(data)
            login(request, user)
            return Response(serializer.data, status=status.HTTP_200_OK)


class UserLogout(APIView):
    permission_classes = (permissions.AllowAny,)
    authentication_classes = ()
    def post(self, request):
        logout(request)
        return Response(status=status.HTTP_200_OK)


class UserView(APIView):
    permission_classes = (permissions.IsAuthenticated,)
    authentication_classes = (SessionAuthentication,)
    def get(self, request):
        serializer = UserSerializer(request.user)
        return Response({'user': serializer.data}, status=status.HTTP_200_OK)

after a user logs in via :

import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:pfeapp/Mainpage/homeview.dart';

class LoginAPI {
  static Future<void> loginUser(String email, String password, BuildContext context) async {
    const String apiUrl = 'http://192.168.1.3:8000/accounts/login';

    final Map<String, dynamic> data = {
      'email': email,
      'password': password,
    };

    final String encodedData = jsonEncode(data);

    try {
      final http.Response response = await http.post(
        Uri.parse(apiUrl),
        headers: <String, String>{
          'Content-Type': 'application/json; charset=UTF-8',
        },
        body: encodedData,
      );

      if (response.statusCode == 200) {
        final Map<String, dynamic> responseData = json.decode(response.body);
        final String email = responseData['email'];
        final String password=responseData['password'];
        Navigator.pushReplacement(
          context,
          MaterialPageRoute(builder: (context) => HomeView(email: email)),
        );
      } else {
        print('Failed to sign-in. Error: ${response.statusCode}');
      }
    } catch (error) {
      print('Error while signing in: $error');
    }
  }
}

the user then gets forwarded to HomeView, then after selecting a button from a convexappbar he gets forwarded to a ProfileView: for now its just a button that calls the API for testing:

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

class User {
  final String email;
  final String username;

  User({
    required this.email,
    required this.username,
  });
}

class ProfileWidget extends StatefulWidget {
  const ProfileWidget({super.key});

  @override
  _ProfileWidgetState createState() => _ProfileWidgetState();
}

class _ProfileWidgetState extends State<ProfileWidget> {
  late Future<User> futureUser;

  @override
  void initState() {
    super.initState();
    futureUser = fetchUser();
  }

  Future<User> fetchUser() async {
    const String apiUrl = 'http://192.168.1.3:8000/accounts/user'; 

    try {
      final response = await http.get(Uri.parse(apiUrl));

      if (response.statusCode == 200) {
        final jsonData = json.decode(response.body)['user'];
        return User(
          email: jsonData['email'],
          username: jsonData['username'],
        );
      } else {
        throw Exception('Failed to load user data');
      }
    } catch (e) {
      throw Exception('Failed to connect to the server');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Profile'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () {
                setState(() {
                  futureUser = fetchUser();
                });
              },
              child: const Text('Fetch User'),
            ),
            const SizedBox(height: 20),
            FutureBuilder<User>(
              future: futureUser,
              builder: (context, snapshot) {
                if (snapshot.connectionState == ConnectionState.waiting) {
                  return const CircularProgressIndicator();
                } else if (snapshot.hasError) {
                  return Text('Error: ${snapshot.error}');
                } else {
                  return Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Text('Email: ${snapshot.data!.email}'),
                      Text('Username: ${snapshot.data!.username}'),
                    ],
                  );
                }
              },
            ),
          ],
        ),
      ),
    );
  }
}

I've looked into tokens with JWT and set it up in django but i'm unsure if its the solution. i have it functional now per the documentation at:

import 'package:dio/dio.dart';

class AccountApi {
  Future<Response> Authtoken(email, password) async {
    const String api = "http://192.168.1.3:8000/api/token/";
    Response response = await Dio().post(
      api,
      data: {"email": email, "password": password},
      options: Options(
        headers: {"Content-Type": "application/json"},
      ),
    );
    return response;
  }
}
0

There are 0 best solutions below