在Django 2.1中使用login_required装饰器

时间:2019-01-31 09:53:13

标签: python django django-authentication django-2.1

我有一个基本要求,我有一个登录页面,在用户登录后,该页面会重定向到页面。

如果用户未登录,并且他打开了该URL,他将被重定向到登录页面,成功登录后,他将被重定向到他打开的URL。

登录:http://127.0.0.1:8000/w_dashboard/login/

另一页:http://127.0.0.1:8000/w_dashboard/roaster/

我有一个名为w_dashboard的应用。

现在在设置页面中,我已经声明了

Settings.py

STATIC_URL = '/static/'
LOGIN_URL = '/w_dashboard/login/'

Login.html

<div class="login">
            <form action='{% url "login" %}' method="POST">
                {% csrf_token %}
                <input type="text" placeholder="username" name="user" id="user"><br>
                <input type="password" placeholder="password" name="password" id="pwd"><br>
                <input type="submit" value="Login">
            </form>
                <!-- Categories: success (green), info (blue), warning (yellow), danger (red) -->
                {% for message in messages %}
                        <div class="alert alert-{{ category }} alert-dismissible" role="alert">
                            <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span
                                    aria-hidden="true">&times;</span></button>
                            <!-- <strong>Title</strong> --> {{ message }}
                        </div>
                {% endfor %}
        </div>

w_dashboard的URL文件:

from django.urls import path
from . import views
from django.conf.urls import url

urlpatterns = [
    #url(r'^$', views.HomePageView.as_view()),
    url(r'^$', views.LoginPageView.as_view()),
    url(r'^login/$', views.LoginPageView.as_view(), name = 'login'),
    url(r'^roaster/$', views.RoasterPageView.as_view(), name="roaster"),
    url(r'^manual_login/$', views.RoasterPageView.as_view(), name="mLogin"),

]

现在,w_dashboard views.py:

class LoginPageView(TemplateView):
    def get(self, request, *args, **kwargs):
        if request.method == 'GET':
            print("Get request")

            return render(request, 'login.html', context=None)

    def post(self, request, *args, **kwargs):
        if request.method == 'POST':
            print("POST request")
            print(request.POST['user'])
            a = models.login_validate(request.POST['user'],request.POST['password'])
            if a[0] == 0:
                print("inside if ")
                messages.error(request, 'username or password not correct')
                return render(request, 'login.html', context=None)
            elif a[0] == 1:
                print("inside elif")
                user = emp_user()
                user.name = a[1]
                print(user.last_login)
                print(user.name)
                user.save()
                login(request, user)
                return redirect(request.GET.get('next', 'roaster'))
            else:
                print("in else")
                return render(request, 'login.html', context=None)


class RoasterPageView(TemplateView):
    @login_required
    def get(self, request, *args, **kwargs):
        print(request, request.user)
        return render(request, 'roaster.html', context=None)

我在emp_user w_dashboard中有一个自定义型号名称models.py

class emp_user(models.Model):
    name = models.TextField()
    last_login = models.DateTimeField(default=datetime.now)

现在的问题是出现以下错误:

Internal Server Error: /w_dashboard/roaster/
Traceback (most recent call last):
  File "/Users/driftking9987/.conda/envs/w_management/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/Users/driftking9987/.conda/envs/w_management/lib/python3.6/site-packages/django/core/handlers/base.py", line 126, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/Users/driftking9987/.conda/envs/w_management/lib/python3.6/site-packages/django/core/handlers/base.py", line 124, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/driftking9987/.conda/envs/w_management/lib/python3.6/site-packages/django/views/generic/base.py", line 68, in view
    return self.dispatch(request, *args, **kwargs)
  File "/Users/driftking9987/.conda/envs/w_management/lib/python3.6/site-packages/django/views/generic/base.py", line 88, in dispatch
    return handler(request, *args, **kwargs)
  File "/Users/driftking9987/.conda/envs/w_management/lib/python3.6/site-packages/django/contrib/auth/decorators.py", line 20, in _wrapped_view
    if test_func(request.user):
AttributeError: 'RoasterPageView' object has no attribute 'user'
[31/Jan/2019 09:42:42] "GET /w_dashboard/roaster/ HTTP/1.1" 500 72039

任何线索都将有所帮助。我只希望登录页面重定向到烘焙器页面。并且,如果要打开roaster的网址,则应重定向至登录名,然后再次重定向至roaster。

我还需要Roaster中已登录的用户名,以便我可以显示它(正在保存用户,但未提供所需的输出)

而且,如果用户登录,它将登录多长时间?我的意思是,假设我登录后以某种方式正确地重定向到了“烘焙器”页面,那么,如果我手动打开了烘焙器页面,则不应该重定向到登录页面,这种情况可以持续多长时间?

谢谢

3 个答案:

答案 0 :(得分:0)

auth装饰器应用于函数(而不是类中的方法)。对于基于类的视图,应使用LoginRequiredMixin之类的混合。有关示例的更多信息,请参见Django官方文档-https://docs.djangoproject.com/en/2.1/topics/auth/default/

编辑:您还在为用户使用自定义模型-如何实现自定义用户或扩展Django auth使用的用户模型,请参见:https://docs.djangoproject.com/en/2.1/topics/auth/customizing/

答案 1 :(得分:0)

这个答案基本上是针对刚起步的人,可能不是最优化的代码,但至少可以帮助您启动并运行。

首先,让我们在models.py中创建一个自定义模型。

class AuthUser(AbstractBaseUser):
    password = models.CharField(max_length=128)
    last_login = models.DateTimeField(blank=True, null=True)
    is_superuser = models.IntegerField()
    username = models.CharField(unique=True, max_length=150)
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=150)
    email = models.CharField(null=False, unique=True, max_length=254)
    is_staff = models.IntegerField()
    is_active = models.IntegerField()
    date_joined = models.DateTimeField()

    USERNAME_FIELD = 'email'

    class Meta:
        managed = False
        db_table = 'auth_user'

setting.py中进行声明。

STATIC_URL = '/static/'
LOGIN_URL = '/w_dashboard/login/'
AUTH_USER_MODEL = 'w_dashboard.AuthUser'


AUTHENTICATION_BACKENDS = [
    'w_dashboard.auth_backends.MySQLAuthBackend',
]

就我而言,我不得不从mysql表中查询用户名/密码。所以我必须做出相应的更改。

首先,在settings.py中添加数据库详细信息。

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'w_s',
        'USER': 'r09ot',
        'PASSWORD': 'qw5',
        'HOST': '119.00.00.000',
        'PORT': '3306',
    }
}

现在,这将在数据库中创建几个表,并且我们将使用auth_user创建的Django表来存储用户名和密码。

现在,让我们创建自定义后端。创建一个名为auth_backends.py的文件。

添加以下代码:

from django.contrib.auth import get_user_model, backends
from .models import AuthUser


class MySQLAuthBackend:

    def authenticate(self, request, email=None, password=None):
        print("inside auth func")
        usermodel = get_user_model()
        try:
            user = usermodel.objects.get(email=email)
            if not user:
                print("No such user")

            else:
                print("abc")
                if user.password == password:
                    print("password match")
                    return user
            # if user.check_password(password):
            #     return user

        except usermodel.DoesNotExist:
            print("inside except")
            return None

    def get_user(self, pk):
        usermodel = get_user_model()
        try:
            usermodel = get_user_model()
            return usermodel.objects.get(pk=pk)
        except usermodel.DoesNotExist:
            pass

        return None

上面的代码将以用户名“ email”和密码“ password”查询数据库。并返回用户。

现在让我们进入登录功能。

def post(self, request, *args, **kwargs):
    if request.method == 'POST':
        print("POST request")
        print(request.POST['user'])
        user = authenticate(request, email=request.POST['user'], password=request.POST['password'])
        if user is not None:
            print("login success")
            user.save()
            print(user.__dict__)
            login(request, user)
            request.session.set_expiry(20)
            return redirect(request.GET.get('next', 'mLogin'))
        else:
            print("login unsuccess")
            messages.error(request, 'username or password not correct')
            return render(request, 'login.html', context=None)

现在这是最重要的部分。由于我们通过自定义后端身份验证方法对用户进行了身份验证,因此user接受的方式正在被login方法接受。简而言之,让您登录login函数。

现在是login_required的一部分。既然是视图,我们将像这样使用method_decorator

@method_decorator(login_required, name='dispatch')
class ManualLoginPageView(TemplateView):
    def get(self, request, *args, **kwargs):
        print("inside manual login")
        print(request.user.__dict__)
        print(request.user.get_short_name())
        return render(request, 'manualLogin.html', context=None)

也在url.py中,像

一样添加login_required
url(r'^roaster/$', login_required(views.RoasterPageView.as_view()), name="roaster"),

这正在按预期方式工作并执行功能。

答案 2 :(得分:0)

django 具有内置的身份验证和权限访问。

django 装饰器


from django.contrib.auth.decorators import login_required
# Create your views here.

@login_required(login_url='login')
def dashboard (request):
    
     return render(request, 'dash/index.html')

```

this view only access by the logged in user