1.Cookie

平常我们在浏览网页的时候,在需要输入密码的地方,如果已经登陆了一次,并且时间间隔比较近的话,是不需要登陆的,为什么了?这就是Cookie的作用。

Cookie(或Cookies)指某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据(通常经过加密)。

Cookie中不但可以确认用户,还能包含计算机和浏览器的信息,所以一个用户用不同的浏览器登录或者用不同的计算机登录,都会得到不同的cookie信息,

另一方面,对于在同一台计算机上使用同一浏览器的多用户群,cookie不会区分他们的身份,除非他们使用不同的用户名登录。

如果是从软件开发的角度来看Cookie就是保存在浏览器端的键值对。

如何理解Cookie?它是干啥的?

比如你开车回你家小区,之前没办卡每次都要停车,让别人检查进去,这就像登陆web服务器一样,

之后你办理卡,让它自动识别,以后你就不用之前的那样停下来验证身份了,Cookie就像你手中的那张卡,保存了你的信息,

而且系统能够识别,信息并且有效。如果那天系统不认了、或者换代了过期了啥的就像cookie不能用了一样。

Cookie是别人给你的身份证明,不过话说回来,身份证明只是它的一个方面。

下面是一个最简单的登陆验证:使用Cookie可以免去登陆的过程

def login(request):
if request.method == "POST":
user=request.POST.get("username")
pwd =request.POST.get("password")
#检验用户名密码是否正确
if user == "kebi" and pwd == "":
#登陆成功
#本来是直接跳转一个页面的,现在我们给它加上Cookie信息,在跳转的时候
rep = redirect("/index/") # rep.set_cookie("username",user)
#这样直接传值太不安全,Django也提供了加盐的操作
rep.set_signed_cookie("username2",user,salt="haha",max_age=10)
return rep return render(request,"login.html") def index(request):
#当然在这里也可以获取信息
# user = request.COOKIES.get("username")
# 这样取出来的是这个kebi:1eed7b:GrTaRGzDQ90BErbMqwupnLXOfko
#怎样原样取出来了?
#还要告诉他用什么盐解开
user=request.get_signed_cookie("username2",None,salt="haha")
if not user:
return redirect("/login/")
return render(request,"index.html",{"username":user})

如果在web端设置Cookie信息,web服务器会在第一次请求的时候,将Cookie信息跟随响应一起发送到客户端的固定路径保存,

至于Cookie里面设置了什么信息就是程序开发者决定的了。

每次客户端的登陆,web服务器都会去固定的路径下去寻找Cookie,如果存在且在且满足条件那么就可以免登陆了。

下面对Cookie的一些操作加以说明:

(1)设置Cookie

rep = HttpResponse(...)
rep = render(request, ...)
#在web服务器处理请求的时候进行Cookie添加 rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt='加密盐',...)

除此之外,还有许多其它的参数:

  • key, 键
  • value='', 值
  • max_age=None, 超时时间
  • expires=None, 超时时间(IE requires expires, so set it if hasn't been already.)
  • path='/', Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
  • domain=None, Cookie生效的域名
  • secure=False, https传输
  • httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)

(2)获取Cookie

request.COOKIES['key']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
  • default: 默认值
  • salt: 加密盐
  • max_age: 后台控制过期时间

(3)删除Cookie

def logout(request):
rep = redirect("/login/")
rep.delete_cookie("user") # 删除用户浏览器上之前设置的usercookie值
return rep

不过Django自带的Cookie加盐的机制太过粗糙,所以一般不怎么使用,都是使用Cookie+Session联合使用。

def check_login(func):
@wraps(func)
def inner(request, *args, **kwargs):
next_url = request.get_full_path()
if request.get_signed_cookie("login", salt="SSS", default=None) == "yes":
# 已经登录的用户...
return func(request, *args, **kwargs)
else:
# 没有登录的用户,跳转刚到登录页面
return redirect("/login/?next={}".format(next_url))
return inner def login(request):
if request.method == "POST":
username = request.POST.get("username")
passwd = request.POST.get("password")
if username == "xxx" and passwd == "dashabi":
next_url = request.GET.get("next")
if next_url and next_url != "/logout/":
response = redirect(next_url)
else:
response = redirect("/class_list/")
response.set_signed_cookie("login", "yes", salt="SSS")
return response
return render(request, "login.html")

Cookie版登陆校验

2.Session

from app01 import models

# Create your views here.

def login(request):
if request.method == "POST":
user = request.POST.get("user")
pwd = request.POST.get("pwd") ret = models.user_info.objects.filter(user=user,pwd=pwd)
if ret:
#如果这个用户已经存在,就设置一个session
request.session["user"] = user
return redirect("/index/") return render(request,"login.html")
#session过程详解
#1.生成一个随机字符串
#2.写cookie,django会将sessionID保存在cookie中
#3.最终的会话信息会保存在django_session,那个sessionID会作为取值的ID def index(request):
#用户要访问主页的时候,首先看他有没有user这个sessionID
user = request.session.get("user")
#如果没有,那么就返回登录页面
if not user:
return redirect("/login/")
#否则返回主页
return render(request,"index.html") def log_out(request):
#这下面的是一种清除的手段,算是较为方便的了
#至于中间实现的过程是由django帮你完成的
#它会帮你先找到当前页面的cookie,然后带着sessionID去数据库中删除
request.session.flush()
return redirect("/login/")
#还有一种是del request.session["user"]
#关键是你先要获取user,比较麻烦 # 注意:
# 不同的用户在同一个浏览器上只会生成一个session信息,
# 既然是会话,那么只有一种对应关系,不可能说多个用户对一个浏览器有多个会话同时存在,
# 那样session的数量就会非常的庞大
# 同一个用户,在不同的浏览器登录会生成多个Session会话信息

 

Django中默认支持Session,其内部提供了5种类型的Session供开发者使用:

  • 数据库(默认)
  • 缓存
  • 文件
  • 缓存+数据库
  • 加密cookie

(1)数据库中的Session

SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默认)

(2)缓存Session

SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置

(3)文件Session

SESSION_ENGINE = 'django.contrib.sessions.backends.file'    # 引擎
SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()

(4)缓存+数据库

SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'        # 引擎

(5)加密Cookie Session

SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'   # 引擎

其它公共设置项:

SESSION_COOKIE_NAME = "sessionid"                       # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)

不管你怎么设置Session,使用方式都一样,下面是一些常用的操作:

def index(request):
# 获取、设置、删除Session中数据
request.session['k1']
request.session.get('k1',None)
request.session['k1'] = 123
request.session.setdefault('k1',123) # 存在则不设置
del request.session['k1'] # 所有 键、值、键值对
request.session.keys()
request.session.values()
request.session.items()
request.session.iterkeys()
request.session.itervalues()
request.session.iteritems() # 用户session的随机字符串
request.session.session_key # 将所有Session失效日期小于当前日期的数据删除
request.session.clear_expired() # 检查 用户session的随机字符串 在数据库中是否
request.session.exists("session_key") # 删除当前用户的所有Session数据
request.session.delete() request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。

Session版登陆验证

from functools import wraps

def check_login(func):
@wraps(func)
def inner(request, *args, **kwargs):
next_url = request.get_full_path()
if request.session.get("user"):
return func(request, *args, **kwargs)
else:
return redirect("/login/?next={}".format(next_url))
return inner def login(request):
if request.method == "POST":
user = request.POST.get("user")
pwd = request.POST.get("pwd") if user == "alex" and pwd == "alex1234":
# 设置session
request.session["user"] = user
# 获取跳到登陆页面之前的URL
next_url = request.GET.get("next")
# 如果有,就跳转回登陆之前的URL
if next_url:
return redirect(next_url)
# 否则默认跳转到index页面
else:
return redirect("/index/")
return render(request, "login.html") @check_login
def logout(request):
# 删除所有当前请求相关的session
request.session.delete()
return redirect("/login/") @check_login
def index(request):
current_user = request.session.get("user", None)
return render(request, "index.html", {"user": current_user})

Session版登陆验证

3.CBV中加装饰器相关

CBV实现的登陆视图

class LoginView(View):

    def get(self, request):
"""
处理GET请求
"""
return render(request, 'login.html') def post(self, request):
"""
处理POST请求
"""
user = request.POST.get('user')
pwd = request.POST.get('pwd')
if user == 'alex' and pwd == "alex1234":
next_url = request.GET.get("next")
# 生成随机字符串
# 写浏览器cookie -> session_id: 随机字符串
# 写到服务端session:
# {
# "随机字符串": {'user':'alex'}
# }
request.session['user'] = user
if next_url:
return redirect(next_url)
else:
return redirect('/index/')
return render(request, 'login.html')

要在CBV视图中使用我们上面的check_login装饰器,有以下三种方式:

from django.utils.decorators import method_decorator

(1)加在CBV视图的get或post方法上

from django.utils.decorators import method_decorator

class HomeView(View):

    def dispatch(self, request, *args, **kwargs):
return super(HomeView, self).dispatch(request, *args, **kwargs) def get(self, request):
return render(request, "home.html") @method_decorator(check_login)
def post(self, request):
print("Home View POST method...")
return redirect("/index/")

(2)加在dispatch方法上

from django.utils.decorators import method_decorator

class HomeView(View):

    @method_decorator(check_login)
def dispatch(self, request, *args, **kwargs):
return super(HomeView, self).dispatch(request, *args, **kwargs) def get(self, request):
return render(request, "home.html") def post(self, request):
print("Home View POST method...")
return redirect("/index/")

因为CBV中首先执行的就是dispatch方法,所以这么写相当于给get和post方法都加上了登录校验。

(3)直接加在视图类上,但method_decorator必须传 name 关键字参数

如果get方法和post方法都需要登录校验的话就写两个装饰器

from django.utils.decorators import method_decorator

@method_decorator(check_login, name="get")
@method_decorator(check_login, name="post")
class HomeView(View): def dispatch(self, request, *args, **kwargs):
return super(HomeView, self).dispatch(request, *args, **kwargs) def get(self, request):
return render(request, "home.html") def post(self, request):
print("Home View POST method...")
return redirect("/index/")

补充:

CSRF Token相关装饰器在CBV只能加到dispatch方法上

备注:

  • csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
  • csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
from django.views.decorators.csrf import csrf_exempt, csrf_protect

class HomeView(View):

    @method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
return super(HomeView, self).dispatch(request, *args, **kwargs) def get(self, request):
return render(request, "home.html") def post(self, request):
print("Home View POST method...")
return redirect("/index/")

最新文章

  1. 杂项之图像处理pillow
  2. com.sun.xml.internal.ws.server.ServerRtException: Server Runtime Error: java.net.BindException: Cannot assign requested address: bind
  3. 把某一字段更新为连续值的SQL
  4. iOS开发的那些坑
  5. Thrift——初学
  6. Animation Spinner【项目】
  7. hdu 1288 Hat's Tea
  8. SRV记录说明
  9. Sql2008的行列转换之行转列
  10. 安卓Activity、service是否处于同一进程
  11. 【原创】python实现视频内的face swap(换脸)
  12. 数据模型LP32 ILP32 LP64 LLP64 ILP64
  13. BZOJ_1705_[Usaco2007 Nov]Telephone Wire 架设电话线_DP
  14. jackson xml转对象 对象转xml
  15. 【Python实践-1】求一元二次方程的两个解
  16. iOS webview 获取html中的图片地址
  17. 《设计模式》学习&理解&总结
  18. Session & Cookie小知识~
  19. 深入理解JVM(一)编译openJDK
  20. Chapter5 生长因子、受体和癌症

热门文章

  1. Prometheus入门
  2. linux查看mysql运行日志
  3. 【已解决】 iView-admin 动态路由问题
  4. CDN与缓存的归纳理解
  5. 使用wifi连接eclipse进行android程序调试
  6. cpu使用率高问题
  7. 解决 三星Note3 桌面小部件不实时更新/不刷新 的问题
  8. RecyclerView 踩坑
  9. jQuery效果之显示与隐藏
  10. STM32 Option Bytes位 重置为出厂设置