会话
存取Cookies
在Django中处理持久化,大部分时候你会更愿意用高层些的session 和/或 后面要讨论的user 框架。 但在此之前,我们需要停下来在底层看看如何读写cookies。 这会帮助你理解本章节后面要讨论的工具是如何工作的,而且如果你需要自己操作cookies,这也会有所帮助。
读取已经设置好的cookies极其简单。 每一个
HttpRequest
对象都有一个
COOKIES
对象,该对象的行为类似一个字典,你可以使用它读取任何浏览器发送给视图(view)的cookies。
def show_color(request):
if favorite_color in request.COOKIES:
return HttpResponse(Your favorite color is %s % request.COOKIES[favorite_color])
else:
return HttpResponse(You don't have a favorite color.)
写cookies稍微复杂点。 你需要使用 HttpResponse对象的 set_cookie()方法。 这儿有个基于 GET 参数来设置
def set_color(request):
if favorite_color in request.GET:
# Create an HttpResponse object...
response = HttpResponse(Your favorite color is now %s % request.GET[favorite_color])
# ... and set a cookie on the response
response.set_cookie(favorite_color, request.GET[favorite_color])
return response
else:
return HttpResponse(You didn't give a favorite color.)
你可以给 response.set_cookie() 传递一些可选的参数来控制cookie的行为。
Django的 Session 框架
由于存在的限制与安全漏洞,cookies和持续性会话已经成为Web开发中令人头疼的典范。 好消息是,Django的目标正是高效的"头疼杀手",它自带的session框架会帮你搞定这些问题。
你可以用session 框架来存取每个访问者任意数据, 这些数据在服务器端存储,并对cookie的收发进行了抽象。 Cookies只存储数据的哈希会话ID,而不是数据本身,从而避免了大部分的常见cookie问题。
打开 Sessions功能
Sessions 功能是通过一个中间件和一个模型(model)来实现的。 要打开sessions功能,需要以下几步操作:
编辑 MIDDLEWARE_CLASSES 配置,确保 MIDDLEWARE_CLASSES 中包含 'django.contrib.sessions.middleware.SessionMiddleware'。
确认 INSTALLED_APPS 中有 'django.contrib.sessions' (如果你是刚打开这个应用,别忘了运行 manage.py syncdb )
如果项目是用 startproject 来创建的,配置文件中都已经安装了这些东西,除非你自己删除,正常情况下,你无需任何设置就可以使用session功能。
如果不需要session功能,你可以删除 MIDDLEWARE_CLASSES 设置中的 SessionMiddleware 和 INSTALLED_APPS 设置中的 'django.contrib.sessions' 。虽然这只会节省很少的开销,但积少成多啊。
在视图中使用Session
SessionMiddleware 激活后,每个传给视图(view)函数的第一个参数
HttpRequest
对象都有一个 session 属性,这是一个字典型的对象。 你可以象用普通字典一样来用它。 例如,在视图(view)中你可以这样用:
# Set a session value:
request.session[fav_color] = blue
# Get a session value -- this could be called in a different view,
# or many requests later (or both):
fav_color = request.session[fav_color]
# Clear an item from the session:
del request.session[fav_color]
# Check if the session has a given key:
if fav_color in request.session:
设置测试Cookies
就像前面提到的,你不能指望所有的浏览器都可以接受cookie。 因此,为了使用方便,Django提供了一个简单的方法来测试用户的浏览器是否接受cookie。 你只需在视图(view)中调用 request.session.set_test_cookie(),并在后续的视图(view)、而不是当前的视图(view)中检查 request.session.test_cookie_worked() 。
用户与Authentication
通过session,我们可以在多次浏览器请求中保持数据, 接下来的部分就是用session来处理用户登录了。 当然,不能仅凭用户的一面之词,我们就相信,所以我们需要认证。
当然了,Django 也提供了工具来处理这样的常见任务(就像其他常见任务一样)。 Django 用户认证系统处理用户帐号,组,权限以及基于cookie的用户会话。 这个系统一般被称为 auth/auth (认证与授权)系统。 这个系统的名称同时也表明了用户常见的两步处理。 我们需要
- 验证 (认证) 用户是否是他所宣称的用户(一般通过查询数据库验证其用户名和密码)
- 验证用户是否拥有执行某种操作的 授权 (通常会通过检查一个权限表来确认)
根据这些需求,Django 认证/授权 系统会包含以下的部分:
- 用户 : 在网站注册的人
- 权限 : 用于标识用户是否可以执行某种操作的二进制(yes/no)标志
- 组 :一种可以将标记和权限应用于多个用户的常用方法
- Messages : 向用户显示队列式的系统消息的常用方法
打开认证支持
像session工具一样,认证支持也是一个Django应用,放在 django.contrib 中,所以也需要安装。 与session系统相似,它也是缺省安装的,但如果它已经被删除了,通过以下步骤也能重新安装上:
- 根据本章早前的部分确认已经安装了session 框架。 需要确认用户使用cookie,这样sesson 框架才能正常使用。
- 将 'django.contrib.auth' 放在你的 INSTALLED_APPS 设置中,然后运行 manage.py syncdb以创建对应的数据库表。
- 确认 SessionMiddleware 后面的 MIDDLEWARE_CLASSES 设置中包含 'django.contrib.auth.middleware.AuthenticationMiddleware' SessionMiddleware。
登录和退出
Django 提供内置的视图(view)函数用于处理登录和退出 (以及其他奇技淫巧),但在开始前,我们来看看如何手工登录和退出。 Django提供两个函数来执行django.contrib.auth中的动作 : authenticate() 和login()。
认证给出的用户名和密码,使用 authenticate() 函数。它接受两个参数,用户名 username 和 密码 password ,并在密码对给出的用户名合法的情况下返回一个 User 对象。 如果密码不合法,authenticate()返回None。
>>> from django.contrib import auth
>>> user = auth.authenticate(username='john', password='secret')
>>> if user is not None:
... print Correct!
... else:
... print Invalid password.
authenticate() 只是验证一个用户的证书而已。 而要登录一个用户,使用 login() 。该函数接受一个 HttpRequest 对象和一个 User 对象作为参数并使用Django的会话( session )框架把用户的ID保存在该会话中。
from django.contrib import auth
def login_view(request):
username = request.POST.get('username', '')
password = request.POST.get('password', '')
user = auth.authenticate(username=username, password=password)
if user is not None and user.is_active:
# Correct password, and the user is marked active
auth.login(request, user)
# Redirect to a success page.
return HttpResponseRedirect(/account/loggedin/)
else:
# Show an error page
return HttpResponseRedirect(/account/invalid/)
注销一个用户,在你的视图中使用 django.contrib.auth.logout() 。 它接受一个HttpRequest对象并且没有返回值。
from django.contrib import auth
def logout_view(request):
auth.logout(request)
# Redirect to a success page.
return HttpResponseRedirect(/account/loggedout/)
在实际中,你一般不需要自己写登录/登出的函数;认证系统提供了一系例视图用来处理登录和登出。 使用认证视图的第一步是把它们写在你的URLconf中。 你需要这样写:
from django.contrib.auth.views import login, logout
urlpatterns = patterns('',
# existing patterns here...
(r'^accounts/login/$', login),
(r'^accounts/logout/$', logout),
)
限制已登录用户的访问
有很多原因需要控制用户访问站点的某部分。
一个简单原始的限制方法是检查 request.user.is_authenticated() ,然后重定向到登陆页面:
from django.http import HttpResponseRedirect
def my_view(request):
if not request.user.is_authenticated():
return HttpResponseRedirect('/accounts/login/?next=%s' % request.path)
# ...
或者显示一个出错信息:
def my_view(request):
if not request.user.is_authenticated():
return render_to_response('myapp/login_error.html')
# ...
作为一个快捷方式, 你可以使用便捷的 login_required 修饰符:
from django.contrib.auth.decorators import login_required
@login_required
def my_view(request):
# ...
login_required 做下面的事情:
- 如果用户没有登录, 重定向到 /accounts/login/ , 把当前绝对URL作为 next 在查询字符串中传递过去, 例如: /accounts/login/?next=/polls/3/ 。
- 如果用户已经登录, 正常地执行视图函数。 视图代码就可以假定用户已经登录了。
对通过测试的用户限制访问
限制访问可以基于某种权限,某些检查或者为login视图提供不同的位置,这些实现方式大致相同。
一般的方法是直接在视图的 request.user 上运行检查。 例如,下面视图确认用户登录并是否有 polls.can_vote权限:
def vote(request):
if request.user.is_authenticated() and request.user.has_perm('polls.can_vote')):
# vote here
else:
return HttpResponse(You can't vote in this poll.)
并且Django有一个称为 user_passes_test 的简洁方式。它接受参数然后为你指定的情况生成装饰器。
def user_can_vote(user):
return user.is_authenticated() and user.has_perm(polls.can_vote)
@user_passes_test(user_can_vote, login_url=/login/)
def vote(request):
# Code here can assume a logged-in user with the correct permission.
...
user_passes_test 使用一个必需的参数: 一个可调用的方法,当存在 User 对象并当此用户允许查看该页面时返回 True 。 注意 user_passes_test 不会自动检查 User