Enforcing guest user to view only

Hi all,
Is there a simple way to enforce guest user to (view only my site pages without adding to database) I don’t want to do like the following code

{% if request.user.role == guest %}
    # do something
{% else %}
   # do another things
{% endif %}

Or even by

{% if perms.categories.add_category %}
   # do anything
{% else %}
  # anything
{% endif %}

The above sample will take time to adjust every templates pages
I just ask for saving the time.
Is it possible or I have to do the above scenario ???

You need to be more specific about what the difference is between the two sets of activities.

If it’s as simple as allowing the guest user to GET a view and not POST to it, then you protect the POST method by verifying authentication when handling the POST.

1 Like

From what you’re describing – I’d create a dispatchmixin, similar to django’s login requiredmixin (django.contrib.auth.mixins.LoginRequiredMixin). Put your check for user attributes in there, and then handle your views accordingly per the above suggestion.

The problem is all users must be authenticated.
And I have to give a (username: guest , password: guest) to enable a guest user to login my site , but I have to make him view only without edit or add anything to the database .
I know that this is a silly question and I have some ideas but it will take time to achieve it,
So I asked this question to discuss with you to get the most simple way to fix it.
I’m using vue.js and FBV .
I thought to use it to make every “form” disabled when the guest user enter the page.
But I’m still thinking. Because I want him to view without only POST, so I think that there is another good way instead of make “div” disabled.
I’m thinking also in using decorators. Is there a decorator prevent POST or I have to build it ?, May be this is the near solution from my perspective to fix my issue isn’t it?
Thanks

It’s just python at the end of the day. So, sure. You could create a class and inherit your origin view with some logic to override or “bypass” POST. But that sounds very hacky to me. I think you’d be better off creating separate views for different user types as needed. And using dispatch like I mentioned above to either allow/not allow access, or even redirect as needed.

Is it just one guest user (“guest”), or will you have multiple guest accounts? (That might affect the specifics of your implementation.)

The general recommended solution is to use Django Groups. You can create a group (let’s call it “Permitted Users”), and a Permission (let’s call it “Can_Submit”). You assign all non-guest users to that group.

Either way, you must not rely solely upon making changes to the HTML to prevent submission. There is nothing you (or anyone else) can do that will prevent a malicious user from submitting a form.

You must check the status of the user when handling the POST.

For some ideas on how to do that, see:
See:

You can also use this information in your template to disable fields, forms, etc.

This doesn’t necessarily mean you need to change your templates, you can do this by modifying the Form object in your view. (For example, you could set the disabled attribute on all the fields.) However, this would still allow the form to be submitted.

I’m with @buswedg above - I think you’re best off with checking the status of the user when they do a GET on a page, and send them a “view only” display (not a form) if they’re a guest. It’s much more secure that way.

1 Like

@buswedg Thanks for your reply, I appreciated it so much. But I’m using FBV, I think “dispatchmixin” with CBV

guest users must browse all my site and see all option without (add or edit anything)

I didn’t get this well , please clarify what do you mean ,

I have one account user with username: guest and password: guest, my site have no audience and this scenario deployed for testing not for a production environment

@KenWhitesell Thanks , Your links are good but I tried it all the problem is (GUEST USER must browse and see all options in the site) I can’t redirect him to another URL

My case here is not to prevent guest from visiting the page, The main purpose is to let the guest users to browse and see whole the page with its tabs but without (making save or edit) and I want perform the mission with low efforts
I think the simplest way is to do like this

def add_category(request):
    if request.user.role == 'guest':
        pass
    else:
        # here I can run my code to do the form submission 
    context = {}
return render(request, 'my_html_file', context)  

But what is your opinion in this

def prevent_post_params(params):
    def decorator(func):
        @wraps(func)
        def inner(request, *args, **kwargs):
            if request.user.role == params :
                #return HttpResponseBadRequest()   --->>>>> this line is not what I need
                #### I want here to load my function as it is but with preventing (request.user.role = 'guest')  
                #### from submitting the form
                #### But I can't do it
                return func(request, *args, **kwargs)
        return inner
    return decorator

And I can use it as

@prevent_post_params(params='guest')
def my_form_view(request):
    # my code to submit the form

I have may roles in my CustomUser model (‘admin’, ‘owner’, ‘employee’, ‘guest’, ‘manager’, ‘driver’, …).
In the above decorator I want it to prevent guest role only from “POST” that’s all.

I’m not necessarily suggesting you do that (redirect to another URL). I pointed out those links to highlight the APIs that are available in the different Django modules that would be useful to you creating your own logic for doing this.

The typical pattern for a Django view that handles form input is to accept a request, and then determine whether the request is a GET or POST.

If it’s a GET, it builds the appropriate form and returns a response - usually a rendered page containing that form.

If it’s a POST, it binds the submitted data to the form, saves the data, and then redirects to the page to be displayed after a successful form submission. If the submitted form data was invalid, it rerenders the page as from a GET but with the errors encountered from submitting the form.

See The view as an example of this pattern.

So at a minimum, what you need to do is perform this permission test on the POST handling of the view. Technically, there’s no need for you to alter the form. As long as your view rejects the POST request from ‘guest’, it doesn’t matter what they might enter in on the form or what buttons they push.

Side note: The decorator you have posted here essentially replicates functionality already available in Django. You can use the user_passes_test decorator to call a function that checks for the right combination of verb (GET or POST) and user.

@KenWhitesell Sorry for late .

First I want thanking you for your time and efforts, really I appreciate it so much …
It seems you illustrate this issue in details (as we have known you in solving problems in this forum).

In my search after I ask my question I found (Django groups(as you said or recommend), decorators like (user_passes_test (also as you recommend), and many scenarios as I mention in my original post)).
But I want the most simple way to perform this mission without any complicated procedures . I know that (you and buswedg) talked about security issues and I’m with you completely and I have many benefits here from our discussion , it enriches my knowledge .
Finally I choose the next code to apply in my view and in the templates

{% url 'categories:add_new_category' as add_category_url %}
{% url 'categories:edit_new_category' qs.id as edit_category_url %}

{% if request.path == add_category_url %}
   <button {% if role == guest %} type="button" {% else %} type="submit" {% endif %} class="btn btn-primary" id="btn-save">
     <i class="fas fa-save"></i> 
      </button>
{% elif request.path == edit_category_url %}
     <button  {% if role == guest %} type="button" {% else %} type="submit" {% endif %} :class="[[!isEdit ? 'btn btn-default':'btn btn-primary' ]]" id="btn-save" :disabled="!isEdit ? true:false">
     <i class="fas fa-save"></i>
     </button>
{% endif %}

and

Many thanks for helping us

That’s slightly different than your original request, but ok - I understand that perspectives change.

(From your original message)

So with that in mind, I will once again point out that this:

Really is unnecessary if you do this:

In my original code I mean that I have to write the code twice (i.e code for guests and for non-guests)

But I can do (in the button tag) simple check to prevent guest user from access submitting the form

<button  {% if role == guest %} type="button" {% else %} type="submit" {% endif %} :class="[[!isEdit ? 'btn btn-default':'btn btn-primary' ]]" id="btn-save" :disabled="!isEdit ? true:false">
     <i class="fas fa-save"></i>
</button>

I think it is enough in my scenario or

def add_category(request):
    if request.user.role == 'guest':
        pass
    else:
        # here I can run my code to do the form submission 

As you suggest …

Any way thanks again for helping me and guide me to the right way