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类的使用和自定义,最后实现登陆的重定向以及跳转!

相关文章
相关标签/搜索