django2.0记录 使用登录装饰器实现访问限制及类视图使用装饰器

背景介绍

python3环境,前后端不分离,前端使用bootstrap2框架,后端使用django2.0框架,包含登录前端代码以及后端实现,只是个人日常记录,仅供参考

目的

访问未登录的视图函数,需要先跳转到登录页面,登陆成功在跳转回来

实现思路

跳转到登录页面很容易,就是登陆成功跳转回来出了问题,原因是登录后的post请求里拿不到之前url中next的值,所以只需要在发起get请求时,将next的值传递到模板的input标签里,type为hidden,之后再用post请求拿回来,就可以了!

前端代码

<div class="row-fluid">
            <div class="login-box">
                <h2 style="text-align: center">后台管理系统</h2>
                <form class="form-horizontal" action="/login/" method="post">
                    {% csrf_token %}
                    <fieldset>

                        <div class="input-prepend" title="Username">
                            <span class="add-on"><i class="halflings-icon user"></i></span>
                            <input class="input-large span10" name="username" id="username" type="text"
                                   placeholder="请输入用户名"/>
                        </div>
                        <div class="clearfix"></div>

                        <div style="padding-bottom: 0" class="input-prepend" title="Password">
                            <span class="add-on"><i class="halflings-icon lock"></i></span>
                            <input class="input-large span10" name="password" id="password" type="password"
                                   placeholder="请输入密码"/>
                        </div>
                        {% if errmsg %}
                            <span style="color: red; padding-left: 120px">{{ errmsg }}</span>
                        {% endif %}
                        <input type="hidden" name="nexturl" value="{{ nexturl }}">
                        <div class="clearfix"></div>
                        <div class="button-login">
                            <button style="text-align: center; width: 356px" type="submit" class="btn btn-primary">登陆
                            </button>
                        </div>
                        <div class="clearfix"></div>
                    </fieldset>
                </form>
                <hr>
            </div><!--/span-->
        </div>

后端实现代码

settings.py
LOGIN_URL = '/login/' # 配置未登录时间登录的跳转地址
url.py
from django.urls import path
from django.contrib.auth.decorators import login_required

from apps.user import views

urlpatterns = [
    path('login/', views.UserLoginView.as_view()),
    path('loginout/', login_required(views.UserLoginOutView.as_view())),
]

login_required 添加登录装饰器,未登录状态下跳转登录页面

view.py
class UserLoginView(View):
    """
    用户登录视图
    """

    def get(self, request):
        nextUrl = request.GET.get("next", "")
        if request.user.is_authenticated:
            if nextUrl:
                return redirect(nextUrl)
            else:
                return HttpResponse('登陆成功')
        else:
            return render(request, 'login/login.html', {'nexturl': nextUrl})

    def post(self, request):
        # 1. 获取参数和判断是否有值

        username = request.POST.get("username")
        password = request.POST.get("password")
        nextUrl = request.POST.get("nexturl", "")

        if not all([username, password, code]):
             # 参数不全
             return render(request, 'login/login.html', {'errmsg': '参数不全'})
        # 校验用户密码
        user = authenticate(request, username=username, password=password)
        if user is not None:
            # 保存用户登录信息
            request.session["is_login"] = True
            request.session["username"] = username
            login(request, user)
            if nextUrl:
                return redirect(nextUrl)
            else:
                return redirect(reverse('app_name:list', ))
        else:
            return render(request, 'login/login.html', {'errmsg': '用户名或者密码错误'})

django为类视图添加登录装饰器的方法

第一种:直接在url上下手。

path('loginout/', login_required(views.UserLoginOutView.as_view())),

第二种:使用method_decorator装饰器

from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator


class LoginRequiredMixin(object):
    '''登录状态校验'''
    @method_decorator(login_required(login_url='/login/'))
    def dispatch(self, request, *args, **kwargs):
        return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)

说明:

method_decorator装饰器,是django自带的一个装饰器,其最主要的作用就是解决装饰器不能直接的装饰类视图函数(method_decorator的作用是为函数视图装饰器补充第一个self参数)。
它具有两个参数,第一个参数是:装饰器本身及它的参数;第二个参数是:给这个类中的哪个函数装饰。
如果你愿意去看一下该装饰器的源码
关于dispatch()函数:在其View源码中,它是起着请求映射分发的作用的,其实在执行as_view()的时候,内部就是在执行的就是self.dispatch()方法,你可以自己重写一下,然后给重写的加上装饰器,就可以在其实施分发前进行了登录验证 了。
使用说明:你需要让你的类视图函数继承:LoginRequiredMixin,且在View之前。
这种方法的使用还可以用于取消部分类视图中的csrf验证(仅列举取消单个视图处理类的csrf验证,如果你需要将很多的处理类都取消csrf的话,可以使用继承)。示例如下(也可以配合method_decorator的第二个参数,直接装饰类):

from django.views import View
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt, csrf_protect


class TestView(View):
    """取消该视图处理类中的csrf验证"""
    @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        return super(TestView, self).dispatch(self, request, *args, **kwargs)

    def get(self, request):
        pass

    def post(self, request):
        pass

第三种:利用继承关系,实现在调用执行视图函数前调用login__required()

from django.contrib.auth.decorators import login_required
class LoginRequiredMixin(object):
    '''登录状态校验'''
    @classmethod
    def as_view(cls, **initkwargs):
        view = super(LoginRequiredMixin, cls).as_view(**initkwargs)
        return login_required(view)

在url最主要的还是要实现:login_required(CommentsView.as_view())
而此时就是利用继承优雅的实现。
使用说明:你需要让你的类视图函数继承:LoginRequiredMixin,且在View之前。

补充

  • login_required的跳转函数:你可以不指定(会使用默认的),也可以在其参数中指定,也可以在settings.LOGIN_URL指定。
  • 第三种和第二种的区别就在于:前者深入到分发过程中,在分发前做了验证;后者在分发后做的验证。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章