# Switch to toggle \`LoginRequiredMixin\` on/off

**URL:** <https://forum.djangoproject.com/t/switch-to-toggle-loginrequiredmixin-on-off/16493>\
**Category:** Forms & APIs\
**Created:** [October 17, 2022, 5:45am UTC](https://forum.djangoproject.com/t/switch-to-toggle-loginrequiredmixin-on-off/16493 "2022-10-17T05:45:44Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![Drone4four](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/drone4four/32/3072_2.png) [@Drone4four](https://forum.djangoproject.com/u/Drone4four)\
**Post date:** [October 17, 2022, 5:45am UTC](https://forum.djangoproject.com/t/switch-to-toggle-loginrequiredmixin-on-off/16493/1 "2022-10-17T05:45:44Z")

</div>

The LoginRequired `mixin` is an incredible feature which does a lot of heavy lifting and enables me to protect my website content from outsiders. The official Django docs explain how to require web visitors to login by adding it as part of a Class Based Views constructor through inheritance: [Using the Django authentication system | Django documentation | Django](https://docs.djangoproject.com/en/4.1/topics/auth/default/#the-loginrequired-mixin).

However that doc is only really detailed enough to get it up and running. It’s simple and straight forward - - which is great. But what if I wanted to grant the Admin user in the Dashboard the option to turn a tickbox to turn the Required Login page on and off?

Is it possible to remove the protected gateway with the flick of a switch by the Admin?

If such a feature is not native to the official library of mixins, where might you people suggest if I were to implement this feature on my own? I’m just curious about the basic architecture of what that might look like.

---

<div class="post-metadata">

**Author:** ![leandrodesouzadev](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/leandrodesouzadev/32/8981_2.png) [@leandrodesouzadev](https://forum.djangoproject.com/u/leandrodesouzadev)\
**Post date:** [October 17, 2022, 11:25am UTC](https://forum.djangoproject.com/t/switch-to-toggle-loginrequiredmixin-on-off/16493/2 "2022-10-17T11:25:50Z")

</div>

Hey there!  
I think that the first question you need to answer yourself is: why some route sometimes needs login protection, and sometimes not? This may lead you to think about the design decision of your app.

But answering your question, is possible to implement this behavior, but you’re going to need to do that yourself.  
Creating the respective models, CBV, or decorators if using function based views.

---

<div class="post-metadata">

**Author:** ![Drone4four](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/drone4four/32/3072_2.png) [@Drone4four](https://forum.djangoproject.com/u/Drone4four)\
**Post date:** [October 17, 2022, 10:22pm UTC](https://forum.djangoproject.com/t/switch-to-toggle-loginrequiredmixin-on-off/16493/3 "2022-10-17T22:22:53Z")

</div>

> [@leandrodesouzadev](#):
>
> I think that the first question you need to answer yourself is: why some route sometimes needs login protection, and sometimes not? This may lead you to think about the design decision of your app.

Thanks for the reply. Although I am not quite sure I understand what you mean. What other potential design decisions are even possible? Where can I learn more about design approaches?

> [@leandrodesouzadev](#):
>
> But answering your question, is possible to implement this behavior, but you’re going to need to do that yourself.  
> Creating the respective models, CBV, or decorators if using function based views.

Would writing my own home-made middleware be necessary as well?

---

<div class="post-metadata">

**Author:** ![leandrodesouzadev](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/leandrodesouzadev/32/8981_2.png) [@leandrodesouzadev](https://forum.djangoproject.com/u/leandrodesouzadev)\
**Post date:** [October 17, 2022, 10:26pm UTC](https://forum.djangoproject.com/t/switch-to-toggle-loginrequiredmixin-on-off/16493/4 "2022-10-17T22:26:42Z")

</div>

I mean, if you’re going to toogle the authentication, then you’re going to have a route that sometimes will be authenticated, and sometimes not. My question is: why would you want something like this? The answer of this question may help you see if you’re designing something wrong or not properly.

Just to be clear, you’re trying to remove the requirement of login, or remove the behavior of redirecting to the login page?

---

<div class="post-metadata">

**Author:** ![Drone4four](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/drone4four/32/3072_2.png) [@Drone4four](https://forum.djangoproject.com/u/Drone4four)\
**Post date:** [October 17, 2022, 10:34pm UTC](https://forum.djangoproject.com/t/switch-to-toggle-loginrequiredmixin-on-off/16493/5 "2022-10-17T22:34:45Z")

</div>

> [@leandrodesouzadev](#):
>
> Just to be clear, you’re trying to remove the requirement of login, or remove the behavior of redirecting to the login page?

I am still misunderstanding.

In my usercase, there is a username/password protected ‘gateway’ page enforced by the `LoginRequiredMixin`. I was intending to grant the superuser the ability to remove the gateway with a _switch_ (toggle check box on/off) in the Admin Dashboard which would instead enable Django serve a different unprotected landing page, further enabling public web visitors _without_ usernames/passwords to travese downwards into the rest of the site and contents.

---

<div class="post-metadata">

**Author:** ![leandrodesouzadev](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/leandrodesouzadev/32/8981_2.png) [@leandrodesouzadev](https://forum.djangoproject.com/u/leandrodesouzadev)\
**Post date:** [October 17, 2022, 10:46pm UTC](https://forum.djangoproject.com/t/switch-to-toggle-loginrequiredmixin-on-off/16493/6 "2022-10-17T22:46:33Z")

</div>

Ok i think that i get what you’re saying.  
Doing this on the admin is totally possible, but you’re going to need to use a different mixin, one that “knows” when the login requirement is on/off.  
And my point here is not whether you can or can’t do this, i’m trying to understand _why_ you want to do this. Because, this is not a common thing, actually it’s really “wild” and prone to errors.  
Imagine that you have some sensitive data on your site, and forgot to toogle the authentication back on?  
Because normally when you make your views login protected is either:

- You want to know which user is performing some action;
- You want to protect some action to a specific type of user
- You want to protect some data from being acessed publicly.

---

<div class="post-metadata">

**Author:** ![Drone4four](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/drone4four/32/3072_2.png) [@Drone4four](https://forum.djangoproject.com/u/Drone4four)\
**Post date:** [October 20, 2022, 12:12am UTC](https://forum.djangoproject.com/t/switch-to-toggle-loginrequiredmixin-on-off/16493/7 "2022-10-20T00:12:39Z")

</div>

> [@leandrodesouzadev](#):
>
> And my point here is not whether you can or can’t do this, i’m trying to understand _why_ you want to do this. Because, this is not a common thing, actually it’s really “wild” and prone to errors.  
> Imagine that you have some sensitive data on your site, and forgot to toogle the authentication back on?

My homemade Django CMS blog web app in prod will house and contain some-what controversial philosophical perspectives and ideas. I have already posted the content and it’s protected with the Login Mixin. Since I am the superuser, only I have access. When I feel the Django website infrastructure is complete and as I continue to prepare the essay content, I intend to share my project (website and prod content) with a small select group of peers and colleagues. Maybe 6 people total.

I figure I can create a single user name and password combo for all 6 to share. So I don’t even need 6 different usernames and passwords. Other than my secured and locked down superuser credentials that I personally use, there will just be one username and pass for my 6 friends to share. The password won’t even adhere to the recommended built-in complexity of the LoginMixin. Instead I will just override the requirements by creating a user name and then with a password which is a 7 character long string with all lower case letters and no special characters and no numbers.

I am not trying to defend against a sophisticated adversary like Russian hackers or the NSA. The purpose of my gateway is merely to keep web crawlers and search engines out until my production content is ready to be revealed publicly.

Another way of looking at my needs for my CMS project is like that of a wedding photographer. When my brother got married a few years ago, the photographer took hundreds of photos. The photographer shared a link to her website which didn’t even require a username. It was just a 10 character long passphrase with weak entropy, but it is just enough to temporarily keep out Google from accessing the content.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [October 21, 2022, 6:34am UTC](https://forum.djangoproject.com/t/switch-to-toggle-loginrequiredmixin-on-off/16493/8 "2022-10-21T06:34:40Z")

</div>

> [@Drone4four](#):
>
> I figure I can create a single user name and password combo for all 6 to share.

Regardless of your intent, you really don’t want to do this.

If any one person has their computers compromised, then you’re in the position of changing that password for everyone wishing to access your blog. And, you won’t even know the source of whatever leak occurs.

Go ahead and create individual accounts for everyone.

But regardless of all this, you haven’t addressed the issue of why you think it’s necessary to create a mechanism to toggle the behavior of the `LoginRequiredMixin`. That mixin needs to be used on _every_ page in the site - not just the landing page. Using it only on the landing page does _not_ prevent access to any other page on the site.

So depending upon what your real underlying requirements are, you do have a couple choices.

You could:

- Create your own subclass of the `LoginRequiresMixin` that checks the setting and alters its behavior accordingly.
- Change your views to use the [UserPassesTestMixin](https://docs.djangoproject.com/en/4.1/topics/auth/default/#django.contrib.auth.mixins.UserPassesTestMixin) and make the status of that test depend upon your setting.

Side note: It’s far more common for a site to be attacked by a bot rather than it being directly targeted. If you have a small private site, you’ll find 90+% of your traffic consisting of blind attempts to run scripts and access pages containing known vulnerabilities on your host.

---

<div class="post-metadata">

**Author:** ![Drone4four](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/drone4four/32/3072_2.png) [@Drone4four](https://forum.djangoproject.com/u/Drone4four)\
**Post date:** [October 31, 2022, 11:36am UTC](https://forum.djangoproject.com/t/switch-to-toggle-loginrequiredmixin-on-off/16493/10 "2022-10-31T11:36:04Z")

</div>

Hi KenWhitesell, thanks for your answer to my questions and for your detailed reply. I have a lot to say and more questions to ask.

> [@KenWhitesell](#):
>
> …you haven’t addressed the issue of why you think it’s necessary to create a mechanism to toggle the behavior of the `LoginRequiredMixin`. That mixin needs to be used on _every_ page in the site - not just the landing page. Using it only on the landing page does _not_ prevent access to any other page on the site.

Thank you for clarifying that `LoginRequiredMixin` is required in all CBV’s. All my CBV’s already include `LoginRequiredMixin` so every page on my site is safely protected.

> [@KenWhitesell](#):
>
> …depending upon what your real underlying requirements are, you do have a couple choices.
> 
> You could:
> 
> - Create your own subclass of the `LoginRequiresMixin` that checks the setting and alters its behavior accordingly.
> - Change your views to use the [UserPassesTestMixin](https://docs.djangoproject.com/en/4.1/topics/auth/default/#django.contrib.auth.mixins.UserPassesTestMixin) and make the status of that test depend upon your setting.

For your first bullet point, when you say “create your own subclass” I am wondering: What level of proficiency in programming Python would be required to implement that? Could you share little bit more about where I could get started on that task with regards to the _general architecture_ of changes or moficiations that might need to be made to achieve an Admin Dashboard switch to turn on/off the Login page?

For your second bullet point, thank you for sharing this reference to the official Python docs. The passage in the doc states:

> _class_ `UserPassesTestMixin` [¶](https://docs.djangoproject.com/en/4.1/topics/auth/default/#django.contrib.auth.mixins.UserPassesTestMixin)  
> When using [class-based views](https://docs.djangoproject.com/en/4.1/topics/class-based-views/), you can use the `UserPassesTestMixin` to do this.  
> `test_func`()[¶](https://docs.djangoproject.com/en/4.1/topics/auth/default/#django.contrib.auth.mixins.UserPassesTestMixin.test_func)
> 
> > You have to override the `test_func()` method of the class to provide the test that is performed. Furthermore, you can set any of the parameters of [`AccessMixin`](https://docs.djangoproject.com/en/4.1/topics/auth/default/#django.contrib.auth.mixins.AccessMixin) to customize the handling of unauthorized users:

```auto
from django.contrib.auth.mixins import UserPassesTestMixin

class MyView(UserPassesTestMixin, View):

    def test_func(self):
        return self.request.user.email.endswith('@example.com')

```

Based on the above quote and code sample, if I pass in the builtin `UserPassesTestMixin` and invoke the class method `test_func`, what should my `endswith()` paramater include? Does this passage suggest that when a web visitor enters a username with an email that ends with a certain domain name, then they can descend down into the rest of the website wihtout having to enter a password? Pardon my novice question but I find that this passage in the Django docs could provide a little more clarity. If I have misunderstood here, could someone kindly elaborate on how to leverage the `UserPassTestMixin` by invoking the `test_func` method to return a request to the user function for an email address ending in a specific domain?

> [@KenWhitesell](#):
>
> Side note: It’s far more common for a site to be attacked by a bot rather than it being directly targeted. If you have a small private site, you’ll find 90+% of your traffic consisting of blind attempts to run scripts and access pages containing known vulnerabilities on your host.

I partially know what you mean. I have setup Google Analytics on a few websites the past and notice that it picks up traffic from all over the world. On these sites I have `noindex,nofollow` in my meta tags in the headers which is a superficial protection from bots. I get that. But what that means is the hits are not coming from Google and if I haven’t shared my website links with anyone, then all that traffic is coming frmo bots. All that HTML tag element does is keep my host and content out of Google search restults which is all I really needed for my other websites.

Those `noindex,nofollow` elements won’t protect against the 10-20 hits it receives on any given week from the kind of hostile bots you are referring to. But how ‘hostile’ are they really? Perhaps ‘attack’ might not be the right word. They aren’t actively trying to brute force my login page credentials. Instead the bots are merely ‘sniffing’ for vulnerabilities. In that case, I’m not too concerned because my content is uninteresting and insignificant to those threat actors even if they were to break into my Django login landing page.

I do my best to keep my Django stack fully updated with the latest versions. My dependabot plugin service for my source code repo on GitHub helps remind me when an Django update becomes available, keeping all potential exploits patched right away.

> [@KenWhitesell](#):
>
> > [@Drone4four](#):
> >
> > I figure I can create a single user name and password combo for all 6 to share.
> 
> Regardless of your intent, you really don’t want to do this.  
> If any one person has their computers compromised, then you’re in the position of changing that password for everyone wishing to access your blog. And, you won’t even know the source of whatever leak occurs.  
> Go ahead and create individual accounts for everyone.

I realize that creating 1 user to be shared by 6 people sounds like a bad idea, generally speaking. But to elaborate on my use case, my intention is to demo my Django CMS website on my tablet at a dinner party. I will then provide the 6 people present with the same easy to remember and obvious username and password combination so they can try my website out themselves on their phones and then read some more of the content when they get home. Then at the 1 week mark, I will revoke the shared user access. So it’s all a temporary measure.

It’s also worth empahsizing this shared user will not have Django Admin access nor will they be able to write or post content. They will only have temporary viewing access rights.

Creating individual accounts for all 6 people with unique passwords, while much more secure and would align with best practices, it would also be very cumbersome and inconvenient. Is it really fair to expect me to create 6 usernames with a unique random password for each, then write them down on 6 different pieces of paper and then hand them out to the 6 individuals present?

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [October 31, 2022, 1:08pm UTC](https://forum.djangoproject.com/t/switch-to-toggle-loginrequiredmixin-on-off/16493/11 "2022-10-31T13:08:40Z")

</div>

> [@Drone4four](#):
>
> I am wondering What level of proficiency in programming Python …

Very little beyond what you already know. Keep in mind that every Model or CBV you create is a subclass of a parent class that you are modifying for your own purposes.

As the scope of what you’re looking to do for this is what I would refer to as "narrow and well-defined’, I’d probably take a direct approach.  
General idea:

- Create a model to contain the indicator of whether logins are required or not.
- Create your admin page to allow for that indicator to be changed
- Create the subclass for LoginRequiredMixin (Start by reviewing the source for it in django.contrib.auth.mixins - the mixin is only about 7 lines long.)
  - Change the `dispatch` method to have the check for `is_authenticated` to only be performed if your indicator defined above is set to do so

- Alternative to the above - don’t subclass it, since this mixin only contains one function, and you’re replacing it. Just create a new class inheriting from AccessMixin with your new `dispatch` method.
- Change all your views to use your new mixin

> [@Drone4four](#):
>
> if I pass in the builtin `UserPassesTestMixin` and invoke the class method `test_func`, what should my `endswith()` paramater include?

A change of terminology is necessary here.

This example isn’t “passing” `UserPassesTestMixin` here, it’s defining a new class, inheriting from both `UserPassesTestMixin` and `view`. It’s then overriding the `test_func` method within that class. And it’s _not_ a classmethod - it’s not tagged as such and it’s accepting self as the first argument. (This, in general, is actually a pretty good example of what needs to be done for the `LoginRequiredMixin` above.)

As an example, don’t take what’s being done _in_ the `test_func` literally. That function needs to return a True/False value, where True will allow the view to be executed.

> [@Drone4four](#):
>
> Does this passage suggest that when a web visitor enters a username with an email that ends with a certain domain name, then they can descend down into the rest of the website wihtout having to enter a password?

Not at all.

First, this is performed on a per-view basis, exactly like the `LoginRequiredMixin` as described in my first response. So this would only apply to those views in which it’s being used.

Second, this specific implementation still requires that the user be logged in. They still needed to provide a valid username/password combination. That’s the only way that `request.user` is going to be populated with an object having an email address.

While I referenced just a specific section of that page in the docs, understanding how authentication works does require an understanding of that entire page with some other pages in the docs - along with a pretty good understanding of Python classes.

> [@Drone4four](#):
>
> But how ‘hostile’ are they really? Perhaps ‘attack’ might not be the right word.

“Attack” is precisely the right word here. If any of those vulnerabilities are discovered and subsequently exploited, then they’re usually able to gain root access to that system.

Are they interested in your content? Probably not.

But what they are interested in is using your computer for their own purposes -

- Crypto mining
- Distribution of illegal materials
- As another bot to be used for DDoS attacks against different hosts
- As another bot to be used to continue to sniff for vulnerable targets
- As a base for making attacks against specific targets

Depending upon how/where you host your server, this could end up

- Costing you some significant amount of money (e.g. AWS),
  - Or legal fees if _your_ host was discovered as part of an attack against a different host. You might be “not guilty”, but you’re still going to need to pay your lawyer.

- Causing your host to be shut down due to violations of your Terms and Conditions,
- Having your host blocked by any number of other sites

Most of these attacks are not against Django-related URLs, other than “/admin”. They’re typically against basic PHP-related urls or a small handful of specific frameworks such as Wordpress.  
They’re also regularly probing for standard ports such as ssh, smtp (imap, pop3), and other services typically exposed to the world. (If you have ssh access to your host, are you checking _those_ logs for attacks?)

I aggressively use fail2ban to block access to hosts attempting to access any of those known urls or ports - my ban list is sitting just less than 500 ip addresses. The point is, securing a host exposed to the internet requires a lot more than just protecting Django.

> [@Drone4four](#):
>
> So it’s all a temporary measure.  
> …  
> They will only have temporary viewing access rights.

Yep - I see that. Seems reasonable for this specific situation.

But, to round this out -

> [@Drone4four](#):
>
> … create 6 usernames with a unique random password for each, then write them down on 6 different pieces of paper and then hand them out to the 6 individuals present?

Depending upon the context, I do it with groups of 15 - 20 on an occasional basis. (I used to do some teaching on a fairly regular basis. I’d have to create student accounts that would need to be good for a week.) If not hand-written, I’ll print the information either on the back of business cards or on an index card. Takes what - 5 minutes? Usernames can follow a simple pattern, and depending upon the expected life for these accounts, the password doesn’t need to be all _that_ secure.

---

<div class="post-metadata">

**Author:** ![Drone4four](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/drone4four/32/3072_2.png) [@Drone4four](https://forum.djangoproject.com/u/Drone4four)\
**Post date:** [November 12, 2022, 12:09am UTC](https://forum.djangoproject.com/t/switch-to-toggle-loginrequiredmixin-on-off/16493/12 "2022-11-12T00:09:09Z")

</div>

Hi @KenWhitesell,

Thanks for providing the general contours of how to write a `LoginRequireMixin` toggle feature for a web app. I am only able to understand your outline vaguely and loosely. I know you said that writing this feature is within reach of someone with a basic proficiency in Python, but I think I still have some ways to go. The intermediary step for me is to work on more `exercism.org` practice problems.

> [@KenWhitesell](#):
>
> But what they are interested in is using your computer for their own purposes -
> 
> - Crypto mining
> - Distribution of illegal materials
> - As another bot to be used for DDoS attacks against different hosts
> - As another bot to be used to continue to sniff for vulnerable targets
> - As a base for making attacks against specific targets
> 
> Depending upon how/where you host your server, this could end up
> 
> - Costing you some significant amount of money (e.g. AWS),
> - Or legal fees if _your_ host was discovered as part of an attack against a different host. You might be “not guilty”, but you’re still going to need to pay your lawyer.
> - Causing your host to be shut down due to violations of your Terms and Conditions,
> - Having your host blocked by any number of other sites
> 
> Most of these attacks are not against Django-related URLs, other than “/admin”. They’re typically against basic PHP-related urls or a small handful of specific frameworks such as Wordpress.

This is a long list of threat actors. I see what you mean. One basic line of defense against these types of attacks is to use an obfuscated `admin/` route. Heroku has this really helpful feature which enables the `admin/` address to be defined as a dynamic configuration variable inside the Heroku dashboard. What I have done is appended an ambiguous string of 12 random characters to the end of `admin` so the only way I can access it is via direct entry like with a bookmark. Since it’s a dynamic environmental variable, when I am testing locally I can still access the Django Admin Dashboard at: `localhost:8000/admin/`. Heroku is great.

You explained some further potential malicious activity carried out by hostile actors on the web:.

> [@KenWhitesell](#):
>
> They’re also regularly probing for standard ports such as ssh, smtp (imap, pop3), and other services typically exposed to the world. (If you have ssh access to your host, are you checking _those_ logs for attacks?) I aggressively use fail2ban to block access to hosts attempting to access any of those known urls or ports - my ban list is sitting just less than 500 ip addresses. The point is, securing a host exposed to the internet requires a lot more than just protecting Django.

My web host is Heroku. There is shell access but it is not ssh. It’s a CLI tool Heroku develops in-house. I trust that on their side, Heroku as a power intermediary keeps their doors secure. The potential risk factor (and you’ll kill me when I tell you this but:) the local client-side package for this Heroku CLI tool that I have installed and am actively using in my development environment to interface with Heroku remotely is a few point releases out of date. I run Desktop Manjaro Linux locally and the package repository maintainer abandoned his responsibilities a few months ago and there hasn’t been anyone who stepped in to take his place. So while my client side shell access tool to interface with Heroku is out of date, I trust that Heroku on the server side keeps their shell access doors tightly secured with fail2ban-like precautions. It’s also worth mentioning that to get this client-server side shell access to connect, it requires 2FA with my mobile device which is an excellent feature that isn’t possible through ssh.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [November 12, 2022, 12:17am UTC](https://forum.djangoproject.com/t/switch-to-toggle-loginrequiredmixin-on-off/16493/13 "2022-11-12T00:17:47Z")

</div>

Oh, absolutely - Heroku does a fine job of managing fundamental security from the perspective of the host, and the changed `admin` URL does resolve 95%+ of Django-focused attacks.

Sounds to me like you’ve got that side of it well covered.
