python-django

it2026-03-17  3

Django

1. cookie session

1. 简介

# 发展史 1. 网站都没有保存用户功能的需求 所有用户访问返回的结果都是一样的 eg: 新闻、博客、文章... 2. 出现了一些需要保存用户信息的网站 eg: 淘宝、支付宝、京东... # 以登陆功能为例 如果不保存用户登陆状态 也就意味着用户每次访问网站都需要重复的输入用户名和密码(你觉得这样的网站你还想用吗?) 当用户第一次登陆成功之后 将用户的用户名密码返回给用户浏览器 让用户浏览器保存在本地,之后访问网站的时候浏览器自动将保存在浏览器上的用户名和密码发送给服务端,服务端获取之后自动验证 早先这种方式具有非常大的安全隐患 优化: 当用户登陆成功之后,服务端产生一个随机字符串(在服务端保存数据,用kv键值对的形式),交由客户端浏览器保存 随机字符串1:用户1相关信息 随机字符串2:用户2相关信息 随机字符串3:用户3相关信息 之后访问服务端的时候,都带着该随机字符串,服务端去数据库中比对是否有对应的随机字符串从而获取到对应的用户信息 但是如果你拿到了截获到了该随机字符串,那么你就可以冒充当前用户 其实还是有安全隐患的 要知道在web领域没有绝对的安全也没有绝对的不安全 # cookie 存在客户端浏览器上的键值对 服务端保存在客户端浏览器上的信息都可以称之为cookie 它的表现形式一般都是k:v键值对(可以有多个) # session 存在服务端的键值对 数据是保存在服务端的并且它的表现形式一般也是k:v键值对(可以有多个) # token 加密的键值对 如果放在客户端浏览器上 它就叫cookie 服务端签发的加密字符串 session虽然数据是保存在服务端的 但是禁不住数据量大 token 服务端不再保存数据 登陆成功之后 将一段用户信息进行加密处理 将加密之后的结果拼接在信息后面 整体返回给浏览器保存 浏览器下次访问的时候带着该信息 服务端自动切去前面一段信息再次使用自己的加密算法 跟浏览器尾部的密文进行比对 # 总结: 1. cookie 就是保存在客户端浏览器上的信息 2. session 就是保存在服务端上的信息 3. session 是基于cookie工作的(其实大部分的保存用户状态的操作都需要使用到cookie)

2. cookie

# cookie的由来 HTTP协议是无状态的,无状态的意思是每次请求都是独立的,它的执行情况和结果与前面的请求和之后的请求都无直接关系,它不会受前面的请求响应情况直接影响,也不会直接影响后面的请求响应情况。 一句有意思的话来描述就是人生只如初见,对服务器来说,每次的请求都是全新的。 状态可以理解为客户端和服务器在某次会话中产生的数据,那无状态的就以为这些数据不会被保留。会话中产生的数据又是我们需要保存的,也就是说要“保持状态”。因此Cookie就是在这样一个场景下诞生 # cookie的概念 其实Cookie是key-value结构,类似于一个python中的字典。 随着服务器端的响应发送给客户端浏览器。 然后客户端浏览器会把Cookie保存起来,当下一次再访问服务器时把Cookie再发送给服务器。 Cookie是由服务器创建,然后通过响应发送给客户端的一个键值对。 客户端会保存Cookie,并会标注出Cookie的来源(哪个服务器的Cookie)。 当客户端向服务器发出请求时,会把所有这个服务器Cookie包含在请求中发送给服务器,这样服务器就可以识别客户端了 注意,不同浏览器之间是不共享Cookie的。 # cookie的原理 由服务器产生内容,浏览器收到请求后保存在本地 当浏览器再次访问时,浏览器会自动带上Cookie,这样服务器就能通过Cookie的内容来判断这个是“谁”了。 # Cookie规范 Cookie大小上限为4KB 一个服务器最多在客户端浏览器上保存20个Cookie 一个浏览器最多保存300个Cookie # Cookie的覆盖 如果服务器端发送重复的Cookie那么会覆盖原有的Cookie 例如: 客户端的第一个请求服务器端发送的Cookie是:Set-Cookie: a=A 第二个请求服务器端发送的Cookie是:Set-Cookie: a=AA,那么客户端只留一个Cookie,即:a=AA。 # 在浏览器中查看cookie 浏览器中按F12 点击 network cookies就能看到

3. session

# Session的由来 Cookie虽然在一定程度上解决了“保持状态”的需求,但是由于Cookie本身最大支持4096字节,以及Cookie本身保存在客户端,可能被拦截或窃取,因此就需要有一种新的东西,它能支持更多的字节,并且保存在服务器,有较高的安全性,这就是Session。 # 问题 基于HTTP协议的无状态特征,服务器根本就不知道访问者是“谁”。那么上述的Cookie就起到桥接的作用 我们可以给每个客户端的Cookie分配一个唯一的id,这样用户在访问时,通过Cookie,服务器就知道来的人是“谁”。然后我们再根据不同的Cookie的id,在服务器上保存一段时间的私密资料,如“账号密码”等等。 # 总结 Cookie弥补了HTTP无状态的不足,让服务器知道来的是“谁”;但是Cookie以文本的形式保存在本地,自身安全性较差;所以我们就通过Cookie识别不同的用户,对应的在Session里保存私密的信息以及超过4096字节的文本 另外,上述所说的Cookie和Session其实是共通性的东西,不限于语言和框架。

4. 会话

# 会话跟踪 会话可以理解为客户端与服务器之间的一次会晤,在一次会晤中可能会包含多次请求和响应。 例如: 你给10086打个电话,你就是客户端,而10086服务人员就是服务器 从双方接通电话那一刻起,会话就开始了,到某一方挂断电话表示会话结束 在通话过程中,你会向10086发出多个请求,那么这多个请求都在一个会话中 在Web中,客户向某一服务器发出第一个请求开始,会话就开始了,直到客户关闭了浏览器,会话结束 在一个会话的多个请求中共享数据,这就是会话跟踪技术 例如: 在一个会话中的请求如下: 请求银行主页 请求登录(请求参数是用户名和密码) 请求转账(请求参数与转账相关的数据) 请求信用卡还款(请求参数与还款相关的数据) 在上述会话中当前用户信息必须在这个会话中共享的,因为登录的是张三,那么在转账和还款时一定是相对张三的转账和还款!这就说明我们必须在一个会话过程中有共享数据的能力。 # 会话路径技术使用Cookie或session完成 HTTP协议是无状态协议,也就是说每个请求都是独立的,无法记录前一次请求的状态 但HTTP协议中可以使用Cookie来完成会话跟踪 在Web开发中,使用session来完成会话跟踪,session底层依赖Cookie技术

2. django中cookie的使用

''' 虽然cookie是服务端告诉客户端浏览器需要保存内容 但是客户端浏览器可以选择拒绝保存 如果禁止了 那么只要是需要记录用户状态的网站登陆功能都无法使用了 ''' # 视图函数的返回值 return HttpResponse() return render() return redirect() # 想要操作cookie 需要利用obj对象 # 1. 操作cookie obj1 = HttpResponse() return obj1 # 2. 操作cookie obj2 = render() return obj2 # 3. 操作cookie obj3 = redirect() return obj3 # 1. 设置cookie 1. obj.set_cookie(key,value) 2. obj.set_signed_cookie(key,value,salt='加密盐') # 2. 获取cookie 1. request.COOKIES.get(key) 2. request.get_signed_cookie(key, default=RAISE_ERROR, # 默认值 salt='', # 加密盐 max_age=None # 后台控制过期时间 ) # 3. 删除cookie(注销功能) obj.delete_cookie(key) # 4. 在设置cookie的时候可以添加一个超时时间 obj.set_cookie('username', 'jason666',max_age=3,expires=3) max_age expires 两者都是设置超时时间的 并且都是以秒为单位 需要注意的是 针对IE浏览器需要使用expires # 示例: 设置cookie def cookie_test(request): # 浏览器向我这个地址发一个请求,就在浏览器写入 name = lqz obj=HttpResponse('ok') obj.set_cookie('name','egon') # 写入到浏览器了,在http响应头里:cookie: name=lqz obj.set_cookie('age','19') # 写入到浏览器了,在http响应头里:cookie: age=19 return obj # 示例: 获取cookie def get_cookie(request): print(request.COOKIES) print(request.COOKIES.get('name')) return HttpResponse('我拿了你传过来的cookie') # 示例: 删除cookie def delete_cookie(request): obj=HttpResponse('我删掉了你name这个cookie ') obj.delete_cookie('name') return obj

3. cookie版登陆校验

1. 路由

path('login/', views.login), path('order/', views.order), path('logout/', views.logout), path('userinfo/', views.userinfo),

2. 视图

""" 需求分析: 用户如果在没有登陆的情况下想访问一个需要登陆的页面 那么先跳转到登陆页面 当用户输入正确的用户名和密码之后 应该跳转到用户之前想要访问的页面去 """ 1. 示例一 # 登录认证装饰器 def login_auth(func): def inner(request, *args, **kwargs): # 登录校验 name = request.COOKIES.get('name') if name: res = func(request, *args, **kwargs) return res else: path = request.get_full_path() return redirect('/login/?returnUrl=%s' % path) return inner # 登录视图函数 def login(request): if request.method == 'GET': return render(request, 'login.html') else: name = request.POST.get('name') password = request.POST.get('password') if name == 'lqz' and password == '123': # 登录成功,重定向 path = request.GET.get('returnUrl') if path: obj = redirect(path) else: obj = redirect('/home/') # 写入cookie obj.set_cookie('name', name) return obj else: return HttpResponse('用户名或密码错误') # def order(request): # name = request.COOKIES.get('name') # if name: # return render(request,'order.html') # else: # return redirect('/login') # 装饰器版本(只要加了装饰器,一旦进入这个视图函数,就表明登录成了) @login_auth def order(request): return render(request, 'order.html') @login_auth def userinfo(request): return render(request, 'userinfo.html') def logout(request): obj = HttpResponse('退出登录成功') obj.delete_cookie('name') return obj 2. 示例二 # 登录认证装饰器 def login_auth(func): def inner(request,*args,**kwargs): # print(request.path_info) # print(request.get_full_path()) # 能够获取到用户上一次想要访问的url target_url = request.get_full_path() if request.COOKIES.get('username'): return func(request,*args,**kwargs) else: return redirect('/login/?next=%s'%target_url) return inner # 登录视图函数 def login(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') if username == 'jason' and password == '123': # 获取用户上一次想要访问的url target_url = request.GET.get('next') # 这个结果可能是None if target_url: obj = redirect(target_url) else: # 保存用户登陆状态 跳转首页 obj = redirect('/home/') # 让浏览器记录cookie数据 obj.set_cookie('username', 'jason666') """ 浏览器不单单会帮你存 而且后面每次访问的时候还会带着它过来 """ # 跳转到一个需要用户登陆之后才能看的页面 return obj return render(request,'login.html') @login_auth def home(request): # 获取cookie信息 判断你有没有 # if request.COOKIES.get('username') == 'jason666': # return HttpResponse("我是home页面,只有登陆的用户才能进来哟~") # 没有登陆应该跳转到登陆页面 # return redirect('/login/') return HttpResponse("我是home页面,只有登陆的用户才能进来哟~")

3. 模板

1. login.html

<form action="" method="post"> <p>用户名:<input type="text" name="name"></p> <p>密码:<input type="password" name="password"></p> <p><input type="submit" value="提交"></p> </form>

2. order.html

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <a href="/logout/">点我退出</a> </body> </html>

3. userinfo.html

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>用户信息页面</h1> </body> </html>

4. django中session的使用

1. 存在于服务端的键值对 session数据是保存在服务端的,给客户端返回的是一个随机字符串 sessionid: 随机字符串 2. 同一个浏览器不允许登录多个账户,不同浏览器可以登录同一个账户 3. session的使用(必须迁移数据) # 在默认情况下操作session的时候需要django默认的一张django_session表 # 数据库迁移命令: python manage.py makemigrations python manage.py migrate # 设置session request.session['key'] = value # 获取session request.session.get('key') # 设置过期时间 request.session.set_expiry() # 括号内可以放四种类型的参数 1. 整数 多少秒 session会在些秒数后失效 2. 日期对象 到指定日期就失效 3. 0 一旦当前浏览器窗口关闭立刻失效 4. None 失效时间就取决于django内部全局session默认的失效时间 # 清除session request.session.delete() # 只删服务端的 客户端的不删 request.session.flush() # 浏览器和服务端都清空(推荐使用) # 示例 增:request.session['name']=lqz 查:request.session['name'] 改:request.session['name']=egon 删:del request.session['name'] 设置过期时间:request.session.set_expiry(10) # django默认session的过期时间是14天 4. session的其它使用 request.session.setdefault('k1',123) request.session.get('name',None) del request.session['k1'] request.session.keys() request.session.values() request.session.items() # 获取那个随机字符串,django_session表中session_key字段 request.session.session_key # 清除过期的session request.session.clear_expired() # 判断这个随机字符串(session_key字段),有没有数据 request.session.exists("session_key") # 删除所有的值,django_session表中删除当前登录者的这条记录 (只删数据库) request.session.delete() # 删除当前的会话数据并删除会话的Cookie(数据库和cookie都删) request.session.flush() 5. django_session表 django_session表中的数据条数是取决于浏览器的 同一个计算机上(IP地址)同一个浏览器只会有一条数据生效 当session过期的时候可能会出现多条数据对应一个浏览器,但是该现象不会持续很久 内部会自动识别过期的数据清除 你也可以通过代码清除 主要是为了节省服务端数据库资源 6. 示例: 设置session request.session['hobby'] = 'girl' """ 运行代码 内部发生的事情 1. django内部会自动帮你生成一个随机字符串 2. django内部自动将随机字符串和对应的数据存储到django_session表中 1. 先在内存中产生操作数据的缓存 2. 在响应结果django中间件的时候才真正的操作数据库 3. 将产生的随机字符串返回给客户端浏览器保存 """ 7. 示例: 获取session request.session.get('hobby') """ 运行代码 内部发生的事情 1. 自动从浏览器请求中获取sessionid对应的随机字符串 2. 拿着该随机字符串去django_session表中查找对应的数据 3. 校验 1. 如果比对上了 则将对应的数据取出并以字典的形式封装到request.session中 2. 如果比对不上 则request.session.get()返回的是None """

5. django中session的配置

def set_cookie(self, key, # 键 value='', # 值 max_age=None, # 传个数字,以秒计,过期时间,有默认值 (6天后过期:60*60*24*5) expires=None, path='/', # 默认 / 表示当前域下的所有路径 domain=None, # 在那个域下有效 secure=False, # 是否Https传输cookie 浏览器将通过HTTPS来回传cookie httponly=False # cookie只支持http传输 ) 1. 数据库Session # 引擎(默认) SESSION_ENGINE = 'django.contrib.sessions.backends.db' 2. 缓存Session # 引擎 SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置 SESSION_CACHE_ALIAS = 'default' 3. 文件Session # 引擎 SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() SESSION_FILE_PATH = None 4. 缓存+数据库 # 引擎 SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' 5. 加密Cookie Session # 引擎 SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' 6. 其他公用设置项 # Session的cookie失效日期2周(默认) SESSION_COOKIE_AGE = 1209600 # 是否关闭浏览器使得Session过期(默认) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认) SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存的路径(默认) SESSION_COOKIE_PATH = "/" # Session的cookie保存的域名(默认) SESSION_COOKIE_DOMAIN = None # 是否Https传输cookie(默认) SESSION_COOKIE_SECURE = False # 是否Session的cookie只支持http传输(默认) SESSION_COOKIE_HTTPONLY = True # 是否每次请求都保存Session,默认修改之后才保存(默认) SESSION_SAVE_EVERY_REQUEST = False

6. CBV加装饰器

# 使用登录认证装饰器 CBV中django不建议直接给类的方法加装饰器 from django.views import View from django.utils.decorators import method_decorator # 用法一 加在类上 指定 name='method' # @method_decorator(login_auth,name='get') # @method_decorator(login_auth,name='post') class UserInfo(View): # 用法二 直接作用于当前类里面所有的方法 @method_decorator(login_auth) def dispatch(self, request, *args, **kwargs): return super().dispatch(request,*args,**kwargs) # 用法三 直接加在方法上 @method_decorator(login_auth) def get(self, request, *args, **kwargs): return HttpResponse('userinfo get') def post(self,request): return HttpResponse('post请求') # 总结 1. 加在类上: @method_decorator(login_auth,name='get') 2. 加在方法上: @method_decorator(login_auth)
最新回复(0)