Yes, I haven't written about this site for a long time. And now I consider it my duty to finish it at any cost. So, we need to develop and add a system of authentication and registration of users to the site. How to do this, and what will it look like?
There is actually nothing complicated here. Think about it, we need to develop the following elements:
Login form
Registration form
Password change form
Logout form
Email confirmation form + template
Password reset form + template
Modal window for the user profile
And, actually, that's all... Although AllAuth does not necessarily need to be integrated into the site, you can implement registration and user management by yourself. It will still be easier. We will only have to implement the frontend part of the site.
I do not really want to overcomplicate and overload this article with the implementation of JWT tokens or the implementation of such user account management architectures as SAML2 or LDAP, or even registration through social networks. This will be in the following projects and articles because it has already turned out to be too big.
That is, in this article I will describe the process of integrating the AllAuth library on a django site with the minimum necessary functionality.
Writing a frontend for the login and registration forms
First, let's prepare the containers in which we will draw our modal windows. Add the following lines of code to the base.html template, right before the "main" tag and after the end of the block with the site header:
In my case, the tag with the data-type="profile" attribute will act as another button in the site header. It will open the user card. The user card will be rendered as a modal window, which will be located in the tag with id="auth-modal".
Now let's connect the new Auth component. This React component will draw modal windows for Login, Registration, the user card, and others. In the component file src/index.js, import:
The component file itself implements a component called Auth, which determines via props which modal window to show and how to contact the server, respectively. Surely, there is a simpler and more elegant way to do everything that I have just done, but I just need points of communication with the server from which I can get templates for login and registration, and it is changing the site accordingly. Here is the template file src/components/Auth.js:
Now about the structure and functionality of this module. There is the main exported module - Auth. This is actually a modal window that will contain a user card, a login form, registration forms, and other forms.
There are also two types of functions: on* and fetch*. The first communicates with the server, and the second updates the modal window. It is not necessary to follow this pattern, but it makes the code easier to maintain.
Then there are the updateEmail and updateSession functions. They do exactly what they say: update the email address information and update the current session information. I also added additional functions such as:
getCookie (name) - in case I want to get something and browser cookies.
getCSRFToken () - almost every request requires a CSRF token, so I wrote a separate function
As for the global URLs object. This is not the entire list of available paths to the allauth API, but the minimum required for us. Of course, you can delete it and write all the URLs manually, but that's without me. Moving on.
We must not forget to change the Header component in src/components/header.js. When creating buttons in the site header, I create custom events to which I will connect the modal window, like this:
Insert the highlighted lines of code
Connecting Allauth to the application
First, I would like to note the official documentation, it is complete and quite self-sufficient, although to understand how to use this library specifically on your site, you will need some time and study the official examples. Glory to them, it has some examples.
As always, let's start with installing the necessary packages. The django-allauth package is required, but django-allauth[socialaccount] is not, unless you need to use social networks as a provider for login.
Next, you need to add the following allauth backend to settings.py:
Allauth is designed as an embedded django application, or rather a whole bunch of applications that need to be connected:
It will also be necessary to connect and configure the email backend. For the sole purpose of testing confirmation of sent mail and the ability to reset the password. I will connect the test backend, because it is simply faster and more visual. All messages will be written to files. In the future, we will, of course, change it to a normal email backend.
Add these lines somewhere in settings.py
We are done in the settings.py file. All that remains is to add the paths and make migrations:
In fact, everything is ready, but not quite. I don't need to redirect to a separate page (this is not how myDjango-React site will works). Ideally, I only need the API, and I will do the design myself. And to get access to the allauth API, I will need to tweak some more. Again, the official documentation is quite self-sufficient on this issue.
Add the these apps
Also you need to add a new paths to alluth API.
In the Website/urls.py file
This is not necessary, but still. Since the entire frontend is on React, I don't need extra pages either, which means my site will use allauth in "headless only" mode. To do this, add these lines somewhere in settings.py:
As you may have noticed, we have also added the HEADLESS_FRONTEND_URLS dictionary. It will be needed when we implement email confirmation and password reset, but for now, don't worry about it.
Connecting all together
From this point on, we can do the following: Stupidly write POST requests to the allauth API directly from React (we need literally 4 such requests: to log in /auth/login, to register /auth/signup, to confirm email /auth/email/verify, and to recover password /auth/password/request). In this case, no Django application will be required. Well, almost.
By the way, the entire headless API for making requests can be viewed here. I highly recommend it!!.
But you can do it differently: write a separate application, collect the necessary ModelForms there, render them on the server, and, if necessary, return them to the client. This is much longer but will allow you and me to better understand the internal workings of the allauth package, and moreover, this approach is more flexible in terms of design and fault tolerance of the application.
We will go the first way because React ... >﹏<
Making requests to server(Frontend)
User account page
We will start with the user card page. Of course, it will not be too big and complicated, rather the opposite. Minimum functionality, only necessary data. So far, without linking to other social networks.
First, we get the session status, i.e., we find out whether it is a guest or a registered user. Then, if it is a registered user, we display all the information that may be useful to him (mail, mail type, name). And of course, we add buttons for interaction.
Something like this, registered user
Something like this, not registered user
Each button was linked to a modal window update function. And further we will analyze how this window changes and how the request will be sent to the server.
Form and registration request
For user registration I use 4 fields (one of which is optional) (+1 hidden field, we fill this field with a csrf token). I also change the title and the main button of the modal window.
When you click the PROCEED button, the form is sent. Well, that's briefly, but if expanded, then ... First, the spinner opens, then we collect all the necessary data from the form and check them. We make a POST request to the server along the path /_allauth/browser/v1/auth/signup, i.e., URLs.SIGNUP, having previously left the CSRF token and the required response format in the request header. Then, regardless of the response, we close the form and leave a message to the user about the success of the request.
Form and login request
Login form, simpler than registration. It only requires a username and password.
We create three root elements and change the form itself, the button and the form title accordingly.
We send the form to the address /_allauth/browser/v1/auth/login, i.e. URLs.LOGIN.
Form and request to change password
To change the password we need a separate form. In the fetchPasswordChange function, we change the form, the title and the confirmation button. I also ask to enter the new password twice, just in case...
Before sending a request to change the password, you need to check whether the new passwords match each other. Then make a POST request to /_allauth/browser/v1/account/password/change or URLs.CHANGE_PASSWORD.
Form and password reset request
We update the modal window, i.e. the title, the form and the button itself, of course. To send a password recovery request, you only need to provide an email address.
So how does it work? The user has forgotten his password and wants to recover it. To do this, he sends a POST request to /_allauth/browser/v1/auth/password/request or URLs.REQUEST_PASSWORD_RESET. The server receives this request and sends an email to the specified address.
Password recovery request function
The message has been sent. The message will contain a link to a page with a key in the address. You need to follow this address to get to a page like this.
Out of the box, django-allauth does not provide a page for processing requests for password recovery or email verification (UNLESS, OF COURSE, THIS IS NOT HEADLESS MODE). Otherwise, there will be a redirect to a template page provided in normal mode.
On this page, you need to fill out this form. That is, enter a new password. It would probably be better if I also asked for password confirmation, but this will do. In fact, the form should be sent with two fields:
new password
generated key
In this case, I did not separate the on* and fetch* functions because this is a separate component and the component is quite small. Place this function in ./components/PasswordReset.js
In order for this function to make sense at all, I created a separate component called PasswordReset. I created a component file PasswordReset.js in components and connected it to index.js:
The full source code example of component:
That's not all. You will also need to create an html template on the server side and add the corresponding paths to urls.py
Form and request for email confirmation
My authentication system also supports email validation. There is no particular point in this for now, but in the future it will be quite useful if I, for example, want to know whether this is a valid email address or not.
We must send a PUT request to /_allauth/browser/v1/account/email or URLs.EMAIL
A letter with a link to the page with the key will be sent to the specified email. After going to this page, the user will see the following:
Where you only need to click on a button. Sending the confirmation form is done by this function:
In this case, I did not separate the on* and fetch* functions because this is a separate component and the component is quite small. Place this function in ./components/EmailVerify.js
It sends the key to the server to confirm the email and returns the corresponding message about the verification status.
Just like in the case of password reset, I created a separate component and connected it to index.js:
Here is a full source code of component, EmailVerify:
That's not all. You will also need to create an html template on the server side and add the appropriate paths to urls.py
Form and logout request
And finally, logout of the current session. A DELETE request is send to /_allauth/browser/v1/auth/session or URLs.LOGOUT. An error with code 401 will be returned, so we logout in the catch block.
Setting up routes and views for email verification and password reset
We are almost done. All that remains is to set up the Backend for email verification and password change. Create a new django application, if you don't know how, see here. Name it Authentication and of course connect it to the site project.
Next, create two templates in templates/Authentication, email_verify.html and password_reset.html
Contents of email_verify.html file:
Contents of password_reset.html file:
As you can see, they are almost identical. In principle, I could have made one common template, but I thought that perhaps, in the future, it might be necessary to somehow develop them separately. Now let's add two new urls to Authentication/urls.py:
Note that the paths match those I specified in settings.py earlier. All that remains is to create the corresponding views for these templates, email_verify and password_reset:
Everything is pretty straightforward here, we get the key from the URL, save it to the context when rendering and insert the key as the value of the data-key attribute in the containers. This attribute will then be used by React to send callbacks.
Conclusion
I have finished adding a system for authentication and registration of my guests on the site. Of course, you can also add login and registration via social networks or based on sent confirmation keys. All this will come later and perhaps in other projects, but definitely not in this article, it has already turned out to be too big.
You can download the current and full version of the project site here.
In the next article, we will work on translating our site into other languages, but for now, see you soon. ( ̄︶ ̄)↗
This is an article that is going to introduce you to my new project/webtool, SearchResultParser. Also, from this article, you can navigate to any interesting article for you. See them …
In this article, you will know the way to integrate the React framework into a Django project. As a result, you will get a full-stack app/website. Also in the article, …
I show and tell how to develop a frontend for a site on React with a backend on django. I use MaterialUI and TailwindCSS, with source code and comments.
Used termins
Django template ⟶ This is a text document marked up with a special syntax for inserting new code.
React ⟶ An open-source JavaScript library developed by Facebook for building user interfaces, particularly for single-page applications where you need a fast and interactive user experience. It allows developers to create reusable UI components, manage the state of their applications, and efficiently update the user interface in response to data changes.
React component ⟶ A reusable piece of code in a React application that represents a part of the user interface (UI). Components can be either class-based or functional, and they allow developers to build complex UIs by breaking them down into smaller, manageable pieces.
CORS (Cross-Origin Resource Sharing) ⟶ Is a security feature implemented in web browsers that enables controlled access to resources located outside of a given origin (domain, protocol, and port combination). It is a mechanism that allows web servers to specify who can access their resources and which HTTP methods are permitted for cross-origin requests.
Related questions
What is the purpose of the key attribute when rendering lists?
Keys help React determine which elements have changed, been added, or removed. They must be specified so that React can match array elements over time. The best way to choose a key is to use a string that will clearly distinguish a list item from its siblings. Most often, you will use an ID from your data as a key.
How does prop children work?
Some components do not know their children in advance. This is especially true for components like Sidebar or Dialog, which are like a "box" into which you can put something. For such components, we recommend using a special prop children, which will pass the child elements directly to the output
What is the difference between managed and unmanaged components?
In a controlled component, each state mutation has a handler function associated with it. This makes validating or changing the input value a simple task. Uncontrolled components rely on the DOM as a data source and can be useful when integrating React with non-React code.
Is it possible to create animations in React?
React can be used to create cool animations! For examples, check out the React Transition Group and React Motion libraries.