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指定。
  • 第三種和第二種的區別就在於:前者深入到分發過程中,在分發前做了驗證;後者在分發後做的驗證。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章