django 限制匿名用戶訪問以及重定向

在某些頁面中,咱們不但願匿名用戶可以訪問,例如我的頁面等,這種頁面只容許已經登陸的用戶去訪問,在django中,咱們也有比較多的方式去實現。html

最簡單的,咱們在viewz中去判斷用戶is_authenticated,但這種方法也相對比較笨拙,最理想的的咱們固然不但願這個請求可以進入到咱們view,在這以前就可以返回一個相關的response,而django其實已經給咱們封裝好了相關的函數與類。django

基於fbv模式的login_required裝飾器

def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, 
                    login_url=None):
    # 實際上這個方法也是調用is_authenticated去判斷
    pass
複製代碼

使用方法也很簡單:bash

# fbv模式
from django.contrib.auth.decorators import login_required
@login_required 
def user_info_view(request):
    # 用戶我的界面
    pass
複製代碼

那麼,咱們但願若是是匿名用戶在訪問這個界面後可以重定向到login界面,咱們能夠設置相關參數,login_required裝飾器會默認去讀取settings.LOGIN_URL,並重定向到這個頁面,若是但願更爲靈活,那麼咱們也能夠給裝飾器傳相關參數。函數

# fbv模式
@login_required(login_url='/login/', redirect_field_name='next')
def user_info_view(request):
    # 用戶我的界面
    pass
複製代碼

login_url就是匿名用戶訪問後重定向的url,通常都是login的頁面
redirect_field_name是一個get請求的參數
假設當前頁面會/user/info/
那麼重定向的url爲: /login/?next=/user/info/ 這個參數能夠用於登錄後直接跳轉回這個頁面,後面還會具體介紹!post

基於cbv的LoginRequiredMixin類

博主通常經常使用都是cbv模式,在這個模式下,咱們會重寫get和post方法,理論上能夠用login_required裝飾器去裝飾這兩個方法ui

# cbv模式
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
class UserInfoView(View):
    @method_decorator(login_required(login_url='/login/', redirect_field_name='next'))
    def get(self, request):
    # 獲取用戶我的界面
        pass
複製代碼

login_required是函數裝飾器,method_decorator能夠將函數裝飾器轉化成方法裝飾器。若是這裏還有post請求,那這樣的代碼咱們還要在寫一遍,這樣就顯得有點冗餘,咱們既然用了類來實現,固然經過類的優點來實現!繼承LoginRequiredMixin!url

from django.contrib.auth.mixins import LoginRequiredMixin
class UserInfoView(LoginRequiredMixin, View):
    def get(self, request):
    # 獲取用戶我的界面
        pass
複製代碼

那麼,LoginRequiredMixin是怎麼去實現的呢? 看看源代碼spa

class LoginRequiredMixin(AccessMixin):
    def dispatch(self, request, *args, **kwargs):
        if not request.user.is_authenticated():
            return self.handle_no_permission()
        return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)
複製代碼

其實它重寫了dispatch方法,由於咱們還繼承了view,其實它重寫的view中的dispatch函數,若是知道view的邏輯,你就知道爲何可以這樣實現了!
當咱們在url中,調用你的view類,如UserInfoView.as_view()方法,它會去調用dispatch(),這個方法起到一個分配器的做用,若是get請求,那麼他就調用get方法,若是是post請求,那麼就調用post方法。那麼,在dispatch中去判斷用戶是否登陸,固然能夠起到這個做用。
那既然只是重寫dispatch,咱們也能夠本身實現!code

# 自定義LoginRequiredMixin
class LoginRequiredMixin(object):

    @method_decorator(login_required(login_url='/login/', redirect_field_name='next'))
    def dispatch(self, request, *args, **kwargs):
        return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)
複製代碼

固然,有沒有必要本身實現,那就看各自的需求啦~orm

重定向與跳轉

(login_url='/login/', redirect_field_name='next')
複製代碼

這兩個參數提供了一個重定向與跳轉的url給咱們,當匿名用戶登陸須要登陸的頁面時,就會跳轉到login_url,這個get請求還帶着redirect_field_name參數,值是'next'。 假如他訪問的是我的頁面,那麼跳轉到

http://127.0.0.1/login/?next=/user/info/
複製代碼

咱們能夠經過這個參數,在登陸後直接跳轉到我的頁面。

class LoginView(View):
    """ 用戶登陸邏輯 """
    def get(self, request):
        # 獲取到next參數,渲染到template中,在form表單添加一個hidden類型的元素
        next = request.GET.get('next', '')
        return render(request, "login.html", {'next': next})

    def post(self, request):
        login_form = LoginForm(request.POST)
        if login_form.is_valid():
            user_name = request.POST.get("username", "")
            pass_word = request.POST.get("password", "")
            next = request.POST.get('next', '')
            user = authenticate(username=user_name, password=pass_word)
            if user is not None:
                if user.is_active:
                    login(request, user)
                    if next:
                    # 若是next存在,直接跳轉到指定頁面
                        return HttpResponseRedirect(next)
                    # 不存在跳轉到index界面
                    return HttpResponseRedirect(reverse('index'))
                else:
                    return render(request, "login.html", {"msg": "用戶未激活"})
            else:
                    return render(request, "login.html", {"msg": "用戶名或密碼錯誤"})
        else:
            return render(request, "login.html", {"login_form": login_form})

複製代碼
# login.html template form中添加
<input name="next" type="hidden" value="{{ next }}"/>
複製代碼

普通頁面的登陸跳轉問題

若是普通頁面也想要實現登陸後跳轉回原來的頁面,十分簡單,在request中有個path參數,它表示當前頁面,咱們只須要在跳轉到login界面把這個參數帶上便可

# template
<a class="loginbtn" href="/login/?next={{ request.path }}">登陸</a>
<a class='logoutbtn' href="/logout/?next={{ request.path }}"退出</a>
<a class='registerbtn' href="/register/?next={{ request.path }}"註冊</a>
複製代碼

login的實現邏輯同上面的同樣,其實logout和註冊界面的實現邏輯也是同樣的。

# logout
class LogoutView(View):
    def get(self, request):
        next = request.GET.get('next', '')
        logout(request)
        try:
            return HttpResponseRedirect(next)
        except:
            return HttpResponseRedirect(reverse('index'))

複製代碼

後言

本篇重點在於@login_required裝飾器的使用,以及LoginReqiredMixin類的使用和自定義,最後實現登陸的重定向以及跳轉!

相關文章
相關標籤/搜索