Django笔记三十二之session登录验证操作_当前信息
本文首发于公众号:Hunter后端
原文链接:Django笔记三十二之session登录验证操作
(资料图)
这一篇笔记将介绍 session 相关的内容,包括如何在系统中使用 session,以及利用 session 实现登录认证的功能。
这篇笔记将分为以下几个内容:
session 的使用流程session 的配置和相关方法users 模块的准备session 验证的的实现Session 表介绍登录验证的几种实现形式1、session 的使用流程cookie 和 session 的基本概念这里不做赘述,这里简单讲一下在 Django 中如何使用自定义的模块来实现登录、登出以及仅允许登录用户访问某些接口的操作。
Django 有一套自带的 auth 验证模块,包括用户以及用户及相应的权限的表和操作,我们这里没有用,而是单独自定义一个 user 模块以及相应的功能函数用来实现用户的注册、登录和登出功能。
session 在这里的使用流程大致如下:
1、通过 login 接口,验证成功后,将某些信息写入 session,可以是 user_id,或者是某个你自定义的特定的字段,反正是后续需要进行验证是否登录成功的数据
2、在访问特定的、需要登录才可查看的接口前,先检查前端返回的数据中是否包含我们在上一步中写入的数据来确保用户是处于登录状态,如果是,则允许继续访问,否则返回未登录的信息,提示用户需要先进行登录操作
3、通过 logout 接口,将用户在 login 接口里写入的登录信息抹除,返回登出成功信息
在 Django 中,系统自动为我们准备好了 session 的所有相关的操作,我们只需要在后续的登录操作中往里面写入我们需要验证的数据即可。
Django 这部分为我们准备好的 session 操作也是通过中间件的形式存在的,是 settings.py 的 MIDDLEWARE 的 "django.contrib.sessions.middleware.SessionMiddleware"
如果不指定其他存储方式,session 的数据默认存在于我们的后端表中,这个我们在第一次执行 migrate 的时候已经自动为我们创建了该表,名为 django_session。
表数据的操作和查看我们在后面再详细介绍。
2、session 的配置和相关方法前面已经介绍了 session 的操作流程,这里我们介绍一下 session 的相关配置和方法。
session 配置以下设置都在 settings.py 中设置,事实上,这些 session 的默认配置就差不多可以使用,后续有特殊需求我们可以再来查看,这里只介绍几个我觉得方便我们使用的。
这个地方的官方文档地址在:https://docs.djangoproject.com/zh-hans/3.2/ref/settings/#sessions
SESSION_COOKIE_AGE
session 过期时间,默认为 1209600,即 14 * 24 * 60 * 60,为 14天。
我们可以在 settings.py 中配置 session 的过期时长,也可以在程序中使用方法手动配置过期时长,方法的使用我们后面再介绍。
SESSION_COOKIE_NAME
默认值为 sessionid,在用户登录之后,请求我们系统,请求的 cookie 里会带上 session key-value 的参数,这个 key 就是我们这里的 SESSION_COOKIE_NAME,默认为 sessionid。
如果想改成其他的名称直接定义即可。
SESSION_ENGING
Django 存储 session 具体数据的地方,默认值为 django.contrib.sessions.backends.db,表示存在于数据库,也就是我们前面说的在 django_session 这张表。
也可以存储在文件或者缓存里。
session 方法这里接着介绍一下 session 相关的方法,这些方法的调用一般是在接口里通过 request.session 来操作。
这里我们只是做一下方法的作用和效果的介绍,具体用途我们在之后的示例中再详细说明。
dict 操作
我们可以将 request.session 视作一个 dict,往里面添加 user_id,is_login 等用于标识用户是否登录的信息的时候可以直接操作,比如:
request.session["user_id"] = 1request.session["is_login"] = Truekeys()
输出 request.session.keys() 返回的就是我们在前面往 session 里添加的数据。
同理,request.session.items() 输出的也是我们往里添加的数据的 key-value 的值。
del 操作
当我们使用登出操作时,可以直接使用:
del request.session["user_id"]这种方式会删除 session 中我们保存的 user_id 信息,这样用户在访问我们的接口的时候,如果我们做登录验证的操作,就会找不到已经登录的信息。
之前我们说过,我们的 session 数据会保存在数据库里,这种方式仅仅是删除 session 中某个特定的 key-value,并不会删除 django_session 表中这条数据
而如果想要直接删除这一条 session 数据,则可以使用 flush() 方法
flush()
下面的操作则会直接操作数据库删除这条 session 数据:
request.session.flush()flush() 和 前面的 del 方法都可以用作我们 logout 过程中的操作。
get_expiry_age()
获取 session 过期秒数,这个值就是前面我们在 settings.py 中设置的 SESSION_COOKIE_AGE 的值。
clear_expired()
从 django_session 中移除过期的会话,下面会介绍 Session 这个 model 的相关操作,这里提前说一下这个函数。
django_session 会有一个 expire_date 字段,clear_expired() 这个操作就会删除表里 expire_date 小于当前时间的数据。
3、users 模块的准备前面介绍了 session 的相关配置和方法以及 session 的基本使用流程。接下来我们将介绍如何在系统中使用上 session。
在介绍 session 使用前,我们自定义一个 users application 来做一下相关准备。
新建一个 application 和 相关的配置,在前面的笔记中都有介绍,这里不再做赘述,比如 app 的创建、在 settings.py 里 INSTALLED_APPS 里的定义,和 hunter/urls.py 的 patterns 里新建一条数据,指向 users/urls.py 等操作。
其中,在 hunter/urls.py 中对 users app 的 url 前缀我们定义为 users,如下:
# hunter/urls.pyfrom django.contrib import adminfrom django.urls import path, includeurlpatterns = [ path("admin/", admin.site.urls), path("blog/", include("blog.urls")), path("users/", include("users.urls")),]我们这里在 users/models.py 下新建一个 User model,然后对其进行相关的 migration 操作,使其表添加到数据库中。
# users/models.pyfrom django.db import modelsclass User(models.Model): username = models.CharField(max_length=20, verbose_name="登录用户名", unique=True) password = models.CharField(max_length=256, verbose_name="加密密码")4、session 验证的的实现接下来,我们将新建几个接口:
用户注册接口用户登录接口用户注销接口用户信息接口可以先看下这几个接口的代码总揽,接着我们详细介绍一下接口的操作。
users/urls.pyfrom django.urls import pathfrom users.views import LoginView, RegisterView, LogoutView, UserInfoViewurlpatterns = [ path("register", RegisterView.as_view()), path("login", LoginView.as_view()), path("logout", LogoutView.as_view()), path("user/info", UserInfoView.as_view()),]users/views.pyfrom django.contrib.auth.hashers import make_password, check_passwordfrom django.http import JsonResponsefrom django.views import Viewfrom users.models import Userimport json# 用户注册class RegisterView(View): def post(self, request): request_json = json.loads(request.body) username = request_json.get("username") password = request_json.get("password") if not username or not password: result = {"code": -1, "msg": "username or password not valid"} else: if User.objects.filter(username=username).exists(): result = {"code": -1, "msg": "username exists"} else: User.objects.create(username=username, password=make_password(password)) result = {"code": 0, "msg": "success"} return JsonResponse(result, safe=False)# 用户登录class LoginView(View): def post(self, request): request_json = json.loads(request.body) username = request_json.get("username") password = request_json.get("password") if not username or not password: result = {"code": -1, "msg": "login info error"} else: user = User.objects.filter(username=username).first() if not user: result = {"code": -1, "msg": "username not found"} else: if check_password(password, user.password): result = {"code": 0, "msg": "success"} request.session["username"] = username else: result = {"code": -1, "msg": "password error"} return JsonResponse(result, safe=False)# 用户登出class LogoutView(View): def post(self, request): if request.session.get("username"): del request.session["username"] # request.session.flush() return JsonResponse({"code": 0, "msg": "登出成功"})# 用户信息class UserInfoView(View): def post(self, request): username = request.session.get("username") if username: result = {"code": 0, "msg": f"登录用户为{username}"} status = 200 else: result = {"code": -1, "msg": "用户未登录"} status = 401 return JsonResponse(result, status=status)首先介绍一下,所有请求的参数都是放在 body 里以 json 格式传递,我这里都是通过 postman 来请求测试的。
其次,在请求里,session 的处理可以直接通过 request.session 的方式进行,以下见示例。
用户注册接口在注册接口里,这里做了参数校验的简化,直接 json.loads() 处理 body 的内容,然后通过 Django 自带的加密函数 make_password 将密码以加密的形式保存。
用户登录接口登录接口里,首先是校验账号密码是否正确,判断正确后我们将登录用户的 username 字段写入 session,然后在用户下一次请求的时候就会自动获取该 session。
或者更正确的来说,用户登录在操作 request.session 之后,在返回 response 的时候,系统会在 django_session 里新增或者更新该用户的记录,这条数据有包含 session_key,session_data 和 expire_date 这几个字段。
session_key,在 cookie 的名称是 sessionid,postman 中第一次登录之后,在之后的每一次接口请求都会将sessionid=xx 传给后端,后端就会根据这个 session_key 的值去 django_session 表里查询相应的记录
如果这个 session_key 在表里不存在记录,或者 expire_date 过期了,那么后端系统会自动给其值赋为 None,即认定此次接口请求是未登录状态。
expire_date 字段则是一个时间字段,主要用于判断数据是否过期。
session_data 则是会包含我们写入的数据,比如我们在用户登录的时候,通过 request.session["username"] = username的方式写入了一些特殊的标识,然后将其编码成 session_data 的值存入数据库,那么用户在下次请求接口的时候我们就可以通过解码 session_data,将值取出来用于判断用户是否登录。
将 session_data 解码的方式可以单独通过获取 django_session 的记录然后获取,但是在请求中,Django 为我么做了这些解码工作,我们可以直接通过前面介绍的 request.session.items()的方式来查看在当前登录的 session_data 里写入的 key-value 数据。
注意:前后端并不直接将 session_data 作为值传递,而是会传递 session_key 这个参数,一些校验的数据也都是放在 session_key 对应记录的 session_data 中存在后台的数据库中。
用户信息接口我们假定获取用户信息接口要求用户必须处于登录状态,实际上也是,因为用户不登录无法定位到用户,然后获取用户的信息。
那么我们在进行下一步的实际操作前,我们肯定需要尝试从 session 中获取用户相应的信息,如果获取到了,则判断是处于登录状态,否则是处于未登录状态,无法获取用户信息。
所以我们这里的判断是从 session 中获取 username 字段,通过判断 username 是否有值来判断用户是否处于登录状态。
用户注销接口用户注销,也就是登出接口,我们这里用的是 del 的方式,这个主要是看我们验证用户登录的方式,比如我们是通过向 session 中取值 username 来判断用户是否登录,那么 del request.session["username"]的操作即可实现注销的功能。
注意:这里执行的 del 操作仅仅是删除 session_data 中的 {"username": "xxx"} 的数据,这条 session_key 对应的数据还存在。
可以看到,在这条代码的下一行还有一条是执行的 flush() 操作,这个操作是直接在数据库里删除这条 session 记录,这是一种更为彻底的登出操作。
这里还需要注意的一点是,del 操作的前提是 session 数据里必须要有 username 这个 key,否则会引起报错,所以我们这里用了一个 if 判断逻辑,我们还可以使用 try-except 操作,或者更为彻底的操作是直接使用 flush() 操作。
至此,用户登录登出以及 session 数据的基本使用操作就介绍完毕了,下面我们额外介绍一些操作。
5、Session 表介绍django_session 表的单独获取查看操作一般在程序里不会出现,因为前后端都是通过 cookie 中 sessionid 直接获取到对应的数据,但为了以防万一,或者你对这张表有一些兴趣,这里额外介绍一下如何单独操作这张表里的数据。
django_session 表的引入方式如下:
from django.contrib.sessions.models import Session然后通过 session_key 来获取这条数据,比如 session_key 为 nqu3s71e38279bl5cbgju6sut64tnqmx,就可以:
session_key = "nqu3s71e38279bl5cbgju6sut64tnqmx"session = Session.objects.get(pk=session_key)# session = Session.objects.get(session_key=session_key)其中,我们向 session 里写入的数据都包含在 session.session_data 里,我么可以直接通过 get_decoded() 方法来获取:
session.get_decoded()# {"username": "root"}6、登录验证的几种实现形式获取用户信息这个接口需要用户登录才可以接着获取用户信息,我们这里的操作是直接判断 session 里是否含有 username 字段。
但是如果我们系统里大部分接口都是需要用户先登录才可访问,这样在每个 views 里都要先加这个判断的操作,这样的显然是不实际的。
那么我们可以怎么操作来实现这个重复性的操作呢?
这里提供两个方式,一个是装饰器,一个是写在中间件里。
装饰器实现登录验证其实如果直接使用 Django 自带的登录验证的功能,是可以直接使用系统自带的装饰器的,但是我们这里的表都是手动操作的,所以这个功能的装饰器我这里就自己实现了一个,相关代码如下:
def login_required_manual(func): def wrapper(*args, **kwargs): request = args[1] if not request.session.get("username"): return JsonResponse({"code": -1, "msg": "not login"}, status=401) return func(*args, **kwargs) return wrapperclass UserInfoView(View): @login_required_manual def post(self, request): username = request.session.get("username") return JsonResponse({"code": 0, "msg": f"登录用户{username}"})可以看到,使用了登录验证的装饰器之后,我们的代码都简洁了很多。
我们可以尝试在调用登出接口后,再调用用户信息接口,可以看到系统就自动返回了未登录的信息了。
中间件实现登录验证这里我们假定目前仅仅是注册和登录不需要登录即可访问,然后我们创建一个中间件如下:
# hunter/middlewares/auth_middleware.pyfrom django.http import JsonResponseclass AuthMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): path = request.path # url 路径为 /users/register 和 /users/login 的接口不需要进行判断验证 if path not in [ "/users/register", "/users/login", ]: session = request.session if not session.get("username"): return JsonResponse({"code": -1, "msg": "not login"}, status=401) response = self.get_response(request) return response然后在 hunter/settings.py 里加上这个中间件:
# hunter/settings.pyINSTALLED_APPS = [ ... "hunter.middlewares.auth_middleware.AuthMiddleware", ...]这样,在每个接口请求到达 views 视图前,都会经历这个验证的中间件,这里将接口路径的判断简化成注册接口和登录接口,这两个接口不需要登录即可访问,其他接口都设置成需要登录才可访问。
相比于装饰器的做法,这里更推荐中间件的操作方式,这样首先就不用在每个 views 前加上装饰器,另外,需要登录才可访问的接口都可以在中间件部分统一列举出来,方便查看。
以上就是本篇笔记关于 session 的全部内容。
如果想获取更多后端相关文章,可扫码关注阅读:
标签:
- Django笔记三十二之session登录验证操作_当前信息
- 业务员工作总结怎么写_业务员工作总结
- 卡布西游冲霄怎么超进化 卡布西游冲霄秘技任务|世界焦点
- 人工智能赋能智慧城市 江岸区举行科技成果转化对接活动|每日消息
- 公元与西元有何区别? 西元和公元的区别
- 最资讯丨长江产业投资集团:10.00亿元超短期融资券获准注册
- 假钱分辨最快方法_假钱
- 2023剧场版《哆啦A梦:大雄与天空的理想乡》曝先导海报预告 确认引进档期待定
- 通达动力: 内部控制审计报告 焦点速看
- 三巽集团(06611)首季度累计合同销售金额约为3.84亿元
- 中秋节送什么给父母 中秋节送父母实用礼物推荐_快看
- 全球关注:物企积极布局城市服务赛道 区域深耕型物企优势显著
- 同程旅行发布2022年ESG报告:依托“数实融合”,加速行业数智化 环球即时看
- 全球播报:先进数通(300541)4月27日主力资金净卖出3318.62万元
- 全球最新:教师资格证2023上半年面试准考证什么时间下载?
- 专卖莆田鞋app软件推荐,推荐四个app软件试试
- 百万粉丝网红遭“换脸”后竟成不雅视频主角,记者暗访:5元钱就可“定制”不雅照 世界滚动
- 淡水河谷第一季度EBITDA为37亿美元 同比减少42%|今日关注
- 消息!2023五一天津美术馆门票预约时间+入口
- 【天天快播报】TiDB 7.0 发版
- 新车报讯:LaFerrari继承者法拉利新旗舰原型车谍照曝光|全球最新
- 今日南财市场情绪指数为32.1,市场投资热度提升
- 留学英国 收好这份专业指南
- 黑龙江多少分能上211大学(黑龙江考生多少分能上211大学)|全球观天下
- 将在4月27日上市 新款星途追风官图发布 当前看点
- 观点:甘肃敦煌:多彩课后 快乐成长
- 对景区及民宿酒店开展专项巡视 供电贴心服务助力“放心游”|全球报资讯
- 易方达中证500质量成长ETF净值下跌2.29% 请保持关注
- 法问|补签劳动合同未签期间二倍工资要赔吗
- 石头科技:2022年净利11.83亿元 拟10转4派12.7元
- 环球热文:南非否认:不打算退出
- 焦点播报:人参茶_关于人参茶的介绍
- 最新:2023年建设银行最新定期利率很高,存5万有4500元利息
- 当前快讯:百度学术论文网官网_百度学术官网网址
- 防溺水国旗下的讲话演讲稿小学 国旗下的演讲稿珍惜时间-每日热讯
- 快报:柏诚股份: 关于召开2022年年度股东大会的通知
- 焦点热门:“五一” 游临沧,游玩攻略新鲜出炉!
- 去年浙江公安查办侵犯知识产权案件916起 挽回损失4.5亿元|环球讯息
- 保时捷Matrix矩阵改色膜葵花黄,抢眼又不浮躁的黄色调 天天头条
- 有一种叫云南的生活|五一假期,去普洱感受“入也”咖啡文化
- 飞佳佳/FLYGAGA是哪个国家的品牌_什么档次怎么样
- 关注全球空气污染问题 戴森携手青少年共同守护可持续地球
- 湘潭养老院价格一览表
- 【会员动态】科技驱动!北京住宅院引领装饰行业新变革
- 送给不值一提的过去是什么歌_送给不值一提的过去送给将来更好的自己是什么歌
- 碧桂园被冻结1.3亿财产
- 中工漫评丨“职工事”,商量着办!
- 全球今头条!星云股份(300648)4月26日主力资金净卖出241.18万元
- 新世界电讯_关于新世界电讯简介
- 天天看热讯:权威发布丨“两个不低于”!吉林真金白银奖励科研人员
- 国内商品期货收盘豆二涨超3%
- 当前讯息:揉碎南方,捏成自己 | 新新新青年玩法全开箱
- 新消息丨滑囊炎是什么原因引起_滑囊炎与滑膜炎的区别
- 环球百事通!布克47+8+10太阳力克快船4-1晋级将战掘金,威少18中3
- 恒大汽车2元“甩卖”地产类业务 天津工厂暂缓生产预计5月恢复
- 环球头条:海南儋州:暮春初夏 蔷薇钟花香满城
- 上海警方:王某某的处罚肯定依法依规具体详细内容是什么
- 全球报道:春耕生产有序推进 筑牢粮食丰收基础
- “越夜越精彩”,大咖打卡渝中共话城市夜经济 当前关注
- “走出去”“请进来”“动起来” ——石河子大学多举措促进毕业生高质量充分就业
- 百度内测文心一言官方版本App 世界速读
- 急性鼻窦炎引起头痛怎么缓解_急性鼻窦炎的头痛特点 环球速递
- 恋与制作人白起夏日事件簿 白起夏日事件簿解密洞穴选择
- 天天热讯:水星家纺2022年净利2.78亿元,同比减少27.89% | 年报
- 俄罗斯称将对瑞典驱逐俄外交官作出回应_全球播报
- 第四届联合国世界数据论坛开幕 多重看点引关注
- 打造绿色城市 发展循环经济 当前信息
- 东电公司宣布福岛核污染水排海隧道挖掘完成 今日最新
- 必胜客 长安商场餐厅
- 【天天播资讯】以下哪些用语禁止在商品宣传过程中使用_以下哪些信息禁止出现在食品类目宝贝描述里
- 每日热文:怎么压缩文件夹发给别人邮箱_怎么压缩文件夹
- 适逢周末 多地明确“5.20”照常办公是什么情况
- 世界观焦点:南岳机场航班时刻表2023_衡阳南岳机场航班查询
- 成都:“五一”这些景区要预约、限流
- 临沂红色研学游火热 百名学子走进山村剧场观看实景演艺
- 暖通空调热泵技术_对于暖通空调热泵技术简单介绍 全球要闻
- 透景生命:公司甲型流感病毒相关检测产品已在泰国、欧盟获批,国内暂未有相关产品获证
- 每日头条!八骏图寓意图片讲解_八骏图的意蕴 象征意义
- 今日快讯:狂轰56+9,造15分大逆转!巴特勒打哭字母哥,黑8奇迹即将诞生
- 速递!加快“南阳实践”落地 提升松江区水污染事件应急处置能力
- 广交会凸显我国外贸韧性 热消息
- 先狂分130亿、再定增160亿,硅料毛利75%的通威股份扩产仍缺钱? 世界球精选
- 天天讯息:增额寿的收益,真的有3.5%吗?内行人揭秘真相
- 最新!杭州市区各类高中招生计划公布,有七大变化_全球观焦点
- 微速讯:这钱算白花了?热刺一年前增资1.5亿镑,此后6000万引进理查利森
- 鲤城区开展“头雁”路演活动 社区主干轮番登台|全球今日讯
- 知识图谱应用范围宽广,天眼查示范商业知识图谱商用价值 世界要闻
- 新日月新战略开局良好:逆势实现高质量增长过去5年营收和净利润复合增长率均超20%
- 欧普康视:预计二季度镜片订单有较好增长
- 科华生物聘任天隆公司核心人员为公司副总裁 环球讯息
- 数据库系统工程师有什么用_数据库系统工程师是什么意思简介介绍-每日速看
- 快消息!上海市:给予“元宇宙”领域招商项目不超过项目投资30%的资金支持
- 《长空之王》预售票房突破7087万,打破近5年五一档新片纪录
- 开票税点怎么算_税点6个点怎么算|今热点
- 热爱传递希望 书香点亮梦想 当前简讯
- 因上传原神未公开角色 三名B站UP主被判 赔偿经济损失共计6万元
- 新疆塔城地区额敏县市场监管局牵线搭桥做好叉车检验工作_当前热门
- 公用&电新行业上周:研究汇总和数据跟踪
- 数字北京城,航行在联通2000M的“大运河”-热议
- 全球热头条丨《刺客伍六七》六七和十三这就是命中注定的一对嘛
广告
广告
- 长治襄垣县增收11517万元 提前15天实现首季“开门红”
- 黑龙江讷河新增1例确诊4例无症状 病例详情公布
- 浙江宁波余姚奉化宁海三地开展核酸检测 结果均为阴性
- 浙江湖州南浔三处棋牌室经营者被行拘
- 那年今日 | 一张漫画涨知识之12月13日
- 在宁波乘火车跨省出行须持48小时内核酸阴性证明
- 浙江温州一地发现核酸弱阳性?复采复检结果均为阴性
- 浙江三门发现一名密接者:二次核酸检测结果均为阴性
- 贱卖的发电机 新买的制茶机——安徽水电供区改革两周年回访见闻
- 浙江杭州新增1例新冠肺炎确诊病例 为集中隔离人员
- 2022年研考在即,学硕缩招,专硕时代真的来了?
- 探访杭州核酸检测点:排队高峰多在夜间 医院24小时运转
- 浙江发挥零售药店“哨点”作用 织就疫情防控监测网
- 哈尔滨市本轮疫情首批1名确诊患者出院
- 宁波镇海第三轮全员核酸检测574181人 结果均为阴性
- 陕西新增本土确诊病例1例、境外输入无症状感染者2例
- 齐齐哈尔讷河一地调整为中风险地区
- 浙江新增新冠肺炎确诊病例75例 其中本土74例
- 内蒙古新增本土确诊病例5例 均在呼伦贝尔满洲里市
- 黑龙江无新增确诊病例 新增本土核酸检测初筛阳性人员5例

(资料图)




