Tutorial: Authenticate users with Django in Visual Studio
This article presents Step 5 in the tutorial series Work with the Django web framework in Visual Studio.
Authentication is a common requirement for web apps. The Django Web Project template in Visual Studio provides all the necessary modules for authentication in the Django project's settings.py file. Step 4 in this tutorial series creates a Django web app by using this template. In Step 5, you explore the authentication capabilities of the template and work with the features in the running app.
In Step 5 of the tutorial, you learn how to:
- Explore authentication flow in the Django Web Project template in Visual Studio
- Examine code that supports the authentication process
- Modify code to enable access to Django administrator interfaces
- Run the Django web app and use authentication features
Prerequisites
A Visual Studio solution and a Django web app based on the Django Web Project template (DjangoWeb). Step 4: Use the full Django Web Project template describes how to create this app.
The Django web app must have a super user (administrator) account. Step 4 (Create Django super user) describes how to create the super user credentials.
Review the Prerequisites section in Step 1 of this tutorial series for details about Django template versions, Visual Studio projects versus Django projects, and Python development on Mac.
Explore authentication flow
This section explains the default authentication flow provided by the Django Web Project template for a Django web app.
In Visual Studio, select Debug > Start Debugging (F5) to start the Django web app (DjangoWeb).
When the app opens in the browser, notice the Log in option at the right in the navigation bar:
The running Django app has a navigation bar with three page options, Home, About, and Contact, and a Log in option. The authentication configuration allows any user to see the content on the "Home," "About," and "Contact" pages.
For authenticated access to the Django web app, a designated super user can use the Log in option, which opens the "Log in" page:
After the super user signs in, they can access restricted page views for the site and complete administration tasks:
The super user can use the Log off option to sign out of the Django web app and return to the "Home" page of the Django web app as an unauthenticated user.
In the following sections, you modify the authentication configuration to support Django administrative site access for the super user.
Examine authentication code
Now that you understand the general authentication features of a Django web app, you're ready to examine the underlying code provided by the Django Web Project template:
In Solution Explorer, expand the project's app/templates/app folder. The following steps review several files in this folder.
Open the base template file, layout.html. Scroll to the
<div class="navbar ...>
element and locate the{% include app/loginpartial.html %}
tag.The
{% include %}
tag instructs Django's template system to pull in the contents of the included file at this point in the containing template.Open the loginpartial.html file. Observe how this template uses the conditional tag
{% if user.is_authenticated %}
along with an{% else %}
tag to render different UI elements depending on whether the user is authenticated:{% if user.is_authenticated %} <form id="logoutForm" action="/logout" method="post" class="navbar-right"> {% csrf_token %} <ul class="nav navbar-nav navbar-right"> <li><span class="navbar-brand">Hello {{ user.username }}!</span></li> <li><a href="javascript:document.getElementById('logoutForm').submit()">Log off</a></li> </ul> </form> {% else %} <ul class="nav navbar-nav navbar-right"> <li><a href="{% url 'login' %}">Log in</a></li> </ul> {% endif %}
When you start the app, no super user is authenticated and the template code renders only the Log in link. The link targets the site relative "login" path specified in the Django project's URL file (DjangoWeb/DjangoWeb/urls.py), as described in Step 4 (Examine URL route patterns). The "login" route is mapped to the
django.contrib.auth.views.login
view and the view receives the following data:{ 'template_name': 'app/login.html', 'authentication_form': app.forms.BootstrapAuthenticationForm, 'extra_context': { 'title': 'Log in', 'year': datetime.now().year, } }
This code defines three properties:
template_name
identifies the template for the "Log in" page defined in the app/login.html file. Remember, this link is site relative. The full folder path is app/templates/app/login.html.extra_context
adds information to the default context data given to the template. In this case, the information includes a "Log in" title, along with the date, time, and year.authentication_form
specifies a form class to use with the login procedure. In the template, this property value appears as theform
object. The default value isAuthenticationForm
(fromdjango.contrib.auth.views
), but the Visual Studio project template instead uses the form defined in the project's app/forms.py file:from django import forms from django.contrib.auth.forms import AuthenticationForm from django.utils.translation import ugettext_lazy as _ class BootstrapAuthenticationForm(AuthenticationForm): """Authentication form which uses bootstrap CSS.""" username = forms.CharField(max_length=254, widget=forms.TextInput({ 'class': 'form-control', 'placeholder': 'User name'})) password = forms.CharField(label=_("Password"), widget=forms.PasswordInput({ 'class': 'form-control', 'placeholder':'Password'}))
The form class derives from
AuthenticationForm
and specifically overrides the username and password fields to add placeholder text. The Visual Studio template includes this explicit code on the assumption that you likely want to customize the form, such as adding password strength validation.
When user interaction with the app opens the "Log in" page, the app renders the login.html template. The variables
{{ form.username }}
and{{ form.password }}
render theCharField
forms from theBootstrapAuthenticationForm
class. There's also a built-in section to show validation errors, and a ready-made element for social logins if you choose to add those services:{% extends "app/layout.html" %} {% block content %} <h2>{{ title }}</h2> <div class="row"> <div class="col-md-8"> <section id="loginForm"> <form action="." method="post" class="form-horizontal"> {% csrf_token %} <h4>Use a local account to log in.</h4> <hr /> <div class="form-group"> <label for="id_username" class="col-md-2 control-label">User name</label> <div class="col-md-10"> {{ form.username }} </div> </div> <div class="form-group"> <label for="id_password" class="col-md-2 control-label">Password</label> <div class="col-md-10"> {{ form.password }} </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="hidden" name="next" value="/" /> <input type="submit" value="Log in" class="btn btn-default" /> </div> </div> {% if form.errors %} <p class="validation-summary-errors">Please enter a correct user name and password.</p> {% endif %} </form> </section> </div> <div class="col-md-4"> <section id="socialLoginForm"></section> </div> </div> {% endblock %}
When the user selects Log in on the page form, Django attempts to authenticate the credentials, such as the super user's credentials:
If authentication fails, the user remains on the "Log in" page and the
form.errors
tag is set to true:If authentication succeeds, Django opens the relative URL in the
next
field,<input type="hidden" name="next" value="/" />
, which in this case is the "Home" page (/
).
When the app renders the "Home" page after the user is authenticated, the
user.is_authenticated
property is true when the loginpartial.html template is rendered. In this case, the navigation bar shows a Hello (username) message and the Log off option replaces the Log in option:You can use the
user.is_authenticated
property in other parts of the app code to check authentication.
Access Django administrator interfaces
To check whether the authenticated user is authorized to access specific resources, you need to retrieve user-specific permissions from your database.
The super user or administrator, in particular, is authorized to access the built-in Django administrator interfaces by using the site relative URLs /admin/
and /admin/doc/
. For more information, see Using the Django authentication system (Django docs).
To enable access to the Django administrator interfaces, follow these steps:
Install the
docutils
Python package into your environment. For instructions, see Install packages for the Python environment.In Solution Explorer, expand the Django project folder, DjangoWeb/DjangoWeb/. The following steps update several files in this folder.
Open the Django project's urls.py file and modify the contents as follows:
At the top of the file, add the following package import for URLs to the end of the current list:
from django.conf.urls import include
After the import list, add the following statement:
admin.autodiscover()
Locate the
urlpatterns
definition, and add the following path entry before the'admin/'
entry:path('admin/doc/', include('django.contrib.admindocs.urls')),
Open the Django project's settings.py file and locate the
INSTALLED_APPS
collection. Add the following entry immediately after theapp
entry:'django.contrib.admindocs',
Stop and restart the Django web app.
In the URL address field of the browser, change the page view of the app to the
/admin/
or/admin/doc/
route. These pages provide the super user with access to Django administrative tasks like creating user or group accounts, changing the password, and viewing Django documentation:
Explore log off behavior
There are two ways the super user can log off and end the authenticated session. The Django web app includes the Log off option on the navigation bar and the Django administrative site provides the Log Out option.
Log out from Django administrative site
If the super user is viewing pages on the Django administrative site, they can select Log out on the site navigation bar. The browser refreshes to show the "Logged off" page for the site:
On this page, the user has two options, Home and Log in again. Both options return the user to the "Home" page for the Django administrative site (/admin), where the user is prompted to reenter their credentials.
Log off from Django web app
If the super user is viewing pages in the Django web app, such as "About" or "Contact," they can select Log off on the Django web app navigation bar. The log off behavior is minimal. It simply ends the authenticated session and browses the user back to the app "Home" page.
You can rework the log off behavior so it's more informative for the user:
In Solution Explorer, expand the project's app/templates/app folder, and open the loginpartial.html file.
In the template file, notice that the Log off link simply does an HTTP POST (
action="/logout" method="post"
) operation to the site relative URL path "/login" (href="{% url 'login' %}"
).{% if user.is_authenticated %} <form id="logoutForm" action="/logout" method="post" class="navbar-right"> {% csrf_token %} <ul class="nav navbar-nav navbar-right"> <li><span class="navbar-brand">Hello {{ user.username }}!</span></li> <li><a href="javascript:document.getElementById('logoutForm').submit()">Log off</a></li> </ul> </form> {% else %} <ul class="nav navbar-nav navbar-right"> <li><a href="{% url 'login' %}">Log in</a></li> </ul> {% endif %}
The built-in view
django.contrib.auth.views.logout
function handles this log out process.The current behavior doesn't display any UI that lets the user know they're logged off. The process simply browses the user back to the Django web app "Home" page according to the
'logout/'
path pattern defined in the Django project's URL file (DjangoWeb/DjangoWeb/urls.py):path('logout/', LogoutView.as_view(next_page='/'), name='logout'),
To display a more informative log off confirmation, you can create a "Log off" page for the app.
In the app/templates/app folder, create a new HTML template file named loggedoff.html.
Add the following content to the new template file:
{% extends "app/layout.html" %} {% block content %} <h3>You have been logged off</h3> {% endblock %}
In the Django project's URL file, DjangoWeb/DjangoWeb/urls.py, change the URL pattern for the
'logout/'
path as follows:path('logout/', LogoutView.as_view(template_name='app/loggedoff.html'), name='logout'),
The updated code adds a
template_name
property to work with the new HTML template for the "Logged off" page.Stop and restart the Django web app. Sign in again, and then select Log off. This time, the app shows a more informative message to the user to confirm they're logged off:
Stop the server and close the application browser windows.
Save project to source control
If you've been committing your Visual Studio solution to source control throughout the course of this tutorial series, now is a good time to do another commit. Follow the instructions in Step 2 (commit changes to source control) in this tutorial series.
Your solution should match the tutorial source code on GitHub: Microsoft/python-sample-vs-learning-django.
Use {% csrf_token %} tag in form elements
The {% csrf_token %}
tag includes Django's built-in cross-site request forgery (csrf) protection (Django docs). You usually add this tag to any element that involves POST, PUT, or DELETE request methods, such as a form. The template rendering function (render
) then inserts the necessary protection.
Tutorial review
Congratulations on completing this tutorial on Django in Visual Studio.
In this tutorial, you learned how to:
- Build different types of Django projects by using various templates in Visual Studio
- Create a Django web app with multiple pages
- Use templates to create different routes and page views
- Serve static files, add pages, and use template inheritance
- Provide authenticated access to restricted app pages and features and Django administrative interfaces
Related content
- User authentication in Django (docs.djangoproject.com)
- Tutorial source code on GitHub (Microsoft/python-sample-vs-learning-django)