Django笔记-判断用户是否登录的几种方式
-
一、需求
当用户访问某些网页时(如用户中心),此时需要判断用户是否登录,用户登录才能访问,未登录引导用户跳转至相应的网页或者返回相应数据。
-
二、通过request.user.is_authenticated验证用户是否登录
1、is_authenticated方法说明:
is_authenticated 属于Django User对象中的一个方法,只是Django在内部通过装饰器@property将该方法装饰为可被User对象调用的一个属性。2.is_authenticated方法的实现过程:
用户在登录过后,Django会将用户的id以及use_backen写入到session会话,以一定的有效期存入数据库或者缓存中。并在登录响应cookie中写入一个sessionid=xxxxxxxxx的值。当用户访问用户中心(或其他需要登录才能访问的页面时),我们在视图中调用的request.user.is_authenticated方法就会去获取当前请求对象cookie中sessionid=xxxxx的值,然后通过’xxxx‘这个值去数据库或者缓存中找到当前这个’xxxx’值对应的记录值,然后判断用户登录或存在。3.返回值:True,False
# 路由 path('auth/', AuthenticatedView.as_view()), # 视图 class AuthenticatedView(View): def get(self, request): # 判断用户是否登录 if not request.user.is_authenticated: return http.JsonResponse({ 'errmsg': '用户未登录' }) return http.JsonResponse({ 'errmsg': '登录成功', })
-
三、通过继承LoginRequired Mixin类判断用户是否登录
由于request.user.is_authenticated只返回true、false,每次我们都要编写未登录后的逻辑。这时可以使用LoginRequired Mixin自定义封装未登录后的业务逻辑代码。LoginRequired Mixin是处于django.contrib.auth.mixins中的一个类,它内部封装了调用了request.user.is_authenticated方法,那么未经验证用户的所有请求都会被重定向到登录页面或者显示 HTTP 403 Forbidden 错误
这里我们可以继承至 LoginRequired Mixin类(确保继承至最左边),然后重写handle_no_permission方法,自定义返回相应的用户未登录操作,只要视图继承了该方法就会自动判断用户是否的登陆。
# 封装 class LoginJsondMixin(LoginRequiredMixin): def handle_no_permission(self): return http.JsonResponse({ 'errmsg': '用户未登录' }) # 视图继承 class AuthenticatedView(LoginRequiredMixin, View): def get(self, request): return http.JsonResponse({ 'errmsg': '登录成功', })
-
四、基于(视图函数)通过login_required 装饰器判断用户是否登录
login_required是位于django.contrib.auth.decorators下的一个装饰器,接受三个参数:
1.function=None:
-----------接受需要进行装饰的方法
2.login_url=None:
-----------如果未登录,会重定向到login_url参数传入url地址,默认为全局配置文件下的配置项LOGIN_URL的值
3.redirect_field_name=REDIRECT_FIELD_NAME :
-----------REDIRECT_FIELD_NAME默认为next,该参数的作用是未登录用户访问当前被login_required装饰的视图函数时,那么会在login_url地址的后面加上?next=‘当前视图函数的路由’
4.例如:
-----------当前视图函数的路由为userinfo/,login_url=’/login‘,redirect_field_name=’next,那么在用户未登录的情况下访问该视图,login_required会重定向到/login/?next=/userinfo/小案例测试login_required:
1).模板:index(首页),login(登录),userinfo(用户中心):
index:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>首页</title> </head> <body> <div> <h1>首页</h1> <a href="/userinfo">用户中心</a> </div> </body> </html>
login:
<!DOCTYPE html> <html lang="en"> <head> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>登录</title> </head> <body> <form id='app' method="post"> <label for="">用户名:</label><input type="text" name="username"></br> <label for="">密码:</label><input type="password" name="password"></br> <input type="submit" value="登录" > </form> </body> </html>
userinfo
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>用户中心</title> </head> <body> <div> <h1>hello {{ username }}</h1> </div> </body> </html>
2).路由:
from django.urls import re_path, path from users.views import * urlpatterns = [ path('login/', Login), path('userinfo/', userinfo), path('index/', index) ]
3).视图: Login(),userinfo(),indxe()
# Create your views here. # 首页视图 def index(requset): return render(requset, template_name='index.html') # 登录视图 def Login(request): """ 测试login_required """ if request.method == 'GET': return render(request, template_name='login.html') elif request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') if not all([username, password]): return http.JsonResponse({ 'errmsg': '缺少必传参数' }) # 验证用户 user = authenticate(username=username, password=password) if user is None: return http.JsonResponse({ 'errmsg': '密码错误' }) # 登录用户 login(request, user) next = request.GET.get('next') if next: # 判断是否有next查询字符串,如果有的话登录成功跳转到next对应的地址 response = redirect(next) else: # 否则跳转到首页 response = redirect('/index') # 设置cookies response.set_cookie('username', username, max_age=settings.SESSION_COOKIE_AGE) return response else: return http.JsonResponse({ 'errmsg': '不支持此请求' }) # 对userinfo进行装饰,未登录用户跳转到登录视图(/login/?next=/userinfo/), @login_required(login_url='/login') def userinfo(request): if request.method == 'GET': username = request.COOKIES.get('username') context = { 'username': username } return render(request, template_name='userinfo.html', context=context)
4)效果图:
这里登录时,登录视图函数会判断是否存在next查询字符串,有的话则跳转到相应的地址,没有的话跳转到index -
五、基于视图基类(View)通过login_required 装饰器判断用户是否登录
1.在配置路由时使用login_requiredlogin_required装饰器在上面提到装饰的是一个函数,我们定义的视图函数也是一个函数,那么当我们的视图是基于视图基类View写的话,
那么我们使用login_required装饰器就会发生改变,如下:
视图类:
匹配的路由规则(参数一:路径,参数二:可调用对象(即视图函数)):
因为我们的类继承至视图基类View,在View类里面为我们提供了一个方法as_view(),返回了一个可被调用的对象函数(view),所以我们这里可以通过在配置路由时,用login_required装饰对应自定义的视图类.as_view()。对于View的原理分析可以查看https://www.zmrenwu.com/courses/django-class-based-views-source-code-analysis/materials/37/#as_view2、通过封装as_view函数使用login_required
这里我们自己编写一个类LoginRequired,定义一个类方法as_view,调用View.as_view()方法得到一个函数对象view,通过login_required装饰后返回,接着在自己编写的视图上继承LoginRequired、View,由于多继承的关系,要确保LoginRequired在最左边,这时我们在编写路由时通过LoginRequiredView调用到的就是我们自己编写的as_view()函数,返回的就是已经被装饰后的viw函数对象。并且也具备视图基类View的功能
path('loginrequired/', LoginRequiredView.as_view())
class LoginRequired(object): @classmethod def as_view(cls, **initkwargs): # 自定义as_view()方法中,调用父类的as_view()方法 view = super().as_view() return login_required(view) class LoginRequiredView(LoginRequired, View): def get(self, request): return http.JsonResponse({ 'errmsg': 'ok' })
大概就是以上这样,有不理解或者不对的地方,可以下方留言一起探讨!!
上一篇-Django实现用户退出登录(logout):https://blog.csdn.net/adminwg/article/details/126196630