pbp_django_auth_extended
Forked from pbp_django_auth. A Flutter package for helping students to implement authentication from Django web service in Flutter. This forked (extended) package adds features that is not present in pbp_django_auth packages.
Getting Started
Django's Part
To use the package, you need to make asynchronous JavaScript (AJAX) login view in your Django project.
-
Run
python manage.py startapp authentication
to make a new app module for handling the AJAX login. -
Add
"authentication"
toINSTALLED_APPS
insettings.py
. -
Run
pip install django-cors-headers
to install the required library. -
Add
"corsheaders"
toINSTALLED_APPS
insettings.py
. -
Add
"corsheaders.middleware.CorsMiddleware"
toMIDDLEWARE
insettings.py
. -
Create a new variable in
settings.py
calledCORS_ALLOW_ALL_ORIGINS
and set the value toTrue
(CORS_ALLOW_ALL_ORIGINS=True
). -
Create a new variable in
settings.py
calledCORS_ALLOW_CREDENTIALS
and set the value toTrue
, (CORS_ALLOW_CREDENTIALS=True
). -
Create the following variables in
settings.py
.CSRF_COOKIE_SECURE = True SESSION_COOKIE_SECURE = True CSRF_COOKIE_SAMESITE = 'None' SESSION_COOKIE_SAMESITE = 'None'
-
Create a login view method in
authentication/views.py
.Example Login View
from django.shortcuts import render from django.contrib.auth import authenticate, login as auth_login from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt @csrf_exempt def login(request): username = request.POST['username'] password = request.POST['password'] user = authenticate(username=username, password=password) if user is not None: if user.is_active: auth_login(request, user) # Redirect to a success page. return JsonResponse({ "status": True, "message": "Successfully Logged In!" # Insert any extra data if you want to pass data to Flutter }, status=200) else: return JsonResponse({ "status": False, "message": "Failed to Login, Account Disabled." }, status=401) else: return JsonResponse({ "status": False, "message": "Failed to Login, check your email/password." }, status=401)
This view will set cookies to the user and allow authenticated requests with
@login_required
decorator. -
Create a check_is_anonymous view method in
authentication/views.py
.def check_is_anonymous(request): print(request.user.is_anonymous) return JsonResponse({ "anonymous": request.user.is_anonymous }, status=200)
-
Add url to
authentication/urls.py
path('is-anonymous/', check_is_anonymous, name='check_is_anonymous'),
Flutter's Part
To use the package, modify application root widget to provide the CookieRequest
library to all child widgets by using Provider
.
For example, if the previous app initialization was:
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter App'),
routes: {
"/login": (BuildContext context) => const LoginPage(),
},
);
}
}
Change it to:
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Provider(
create: (_) {
CookieRequest request = CookieRequest(baseUrl: <DJANGO BASE URL>); // DO NOT use trailing '/' here
return request;
},
child: MaterialApp(
title: 'Flutter App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter App'),
routes: {
"/login": (BuildContext context) => const LoginPage(),
},
),
);
}
}
This creates a new Provider
object that will share the CookieRequest
instance with all components in the application.
Usage
To use the package in your project, follow these steps below.
-
Import the
Provider
library and this package to the component.import 'package:provider/provider.dart'; import 'package:pbp_django_auth/pbp_django_auth.dart'; ...
-
Instantiate the
request
object by callingcontext.watch
in the Widgetbuild(BuildContext context)
function.Example
class _LoginPageState extends State<LoginPage> { final _loginFormKey = GlobalKey<FormState>(); bool isPasswordVisible = false; void togglePasswordView() { setState(() { isPasswordVisible = !isPasswordVisible; }); } String username = ""; String password1 = ""; @override Widget build(BuildContext context) { final request = context.watch<CookieRequest>(); // The rest of your widgets are down below ... } }
-
To log in using the package, use the
request.login(url, data)
method.// 'username' and 'password' should be the values of the user login form. final response = await request.login("/auth/login", { 'username': username, 'password': password1, }); if (request.loggedIn) { // Code here will run if the login succeeded. } else { // Code here will run if the login failed (wrong username/password). }
-
To fetch or insert data using the library, use the
request.get(url)
orrequest.post(url, data)
method./* GET request example: */ final response = await request.get(<PATH TO ACCESS (DO NOT INCLUDE BASE URL)>); // The returned response will be a Map object with the keys of the JsonResponse /* POST request example: */ final response = await request.post(<PATH TO ACCESS (DO NOT INCLUDE BASE URL)>, { "data1": "THIS IS EXAMPLE DATA", "data2": "THIS IS EXAMPLE DATA 2", }); // The data argument should be the keys of the Django form. // The returned response will be a Map obejct with the keys of JsonResponse.
You can also use request.postJson(url, encodedJsonData) with jsonEncode function from 'dart:convert' library to send the submitted data without manually converting the data into JSON format one by one.