Niffler

X2.08 16340232-使用 Django session 实现用户登录

Posted By 16340232

Django 的 Session 框架

session 可以存储和获取访问者的数据信息,这些信息保存在服务器上(默认是数据库中),以 cookies 的方式发送和获取一个包含 session ID 的值,并不是用 cookies 传递数据本身,从而避免了大部分的常见 cookie 问题。


启用 session

编辑 settings.py 中的一些配置

MIDDLEWARE_CLASSES 确保其中包含以下内容

'django.contrib.sessions.middleware.SessionMiddleware',

INSTALLED_APPS 是包含

'django.contrib.sessions',

这些是默认启用的。如果不用的话,也可以关掉这个以节省一点服务器的开销。


在视图中使用 session

request.session 可以在视图中任何地方使用,它类似于 python 中的字典

# 创建或修改 session:
request.session[key] = value
# 获取 session:
request.session.get(key,default=None)
# 删除 session
delrequest.session[key] # 不存在时报错`

一个简化的登陆认证:

#  用户登录
@csrf_exempt 
def user_login(request):
    
    if request.method == 'POST':
        # If we didn't post, send the test cookie along with the login form.
        request.session.set_test_cookie()

        # Check that the test cookie worked (we set it below):
        if request.session.test_cookie_worked():

            # The test cookie worked, so delete it.
            request.session.delete_test_cookie()

            # logic to check username/password
            username = request.POST['username']
            password = request.POST['password']

            user = authenticate(username=username, password=password)  #用户验证
            if user:
                login(request, user)  #用户登录
                request.session['user_id'] = user.id
                return HttpResponse("You're logged in.")
            else:
                return HttpResponse("Invalid login details given")
        
        # The test cookie failed, so display an error message. If this
        # were a real site, we'd want to display a friendlier message.
        else:
            return HttpResponse("Please enable cookies and try again.")
        
        
#  用户登出
@csrf_exempt 
@login_required
def user_logout(request):
    try:
        del request.session['user_id']
    except KeyError:
        pass
    return HttpResponse("You're logged out.")

当登陆时验证用户名和密码,并保存用户 id 在 session 中,这样就可以在视图中用 request.session[‘member_id’] 来检查用户是否登陆,当退出的时候,删除掉它。

重写 authenticate 实现邮箱和用户名登录

1、在 setting.py 中进行配置:

AUTHENTICATION_BACKENDS = (
'questionnaire.custom.EmailOrUsernameModelBackend',
)

使用的认证后台通过 AUTHENTICATION_BACKENDS 设置指定。它应该是一个包含 Python 路径名称的元组,它们指向的 Python 类知道如何进行验证。这些类可以位于 Python 路径上任何地方。

2、在 custom.py 中重新定制 authenticate() 方法

class EmailOrUsernameModelBackend(ModelBackend):
    """
    This is a ModelBacked that allows authentication with either a username or an email address.

    """
    def authenticate(self, request, username=None, password=None, **kwargs):
        # n.b. Django <2.1 does not pass the `request`

        user_model = get_user_model()

        if username is None:
            username = kwargs.get(user_model.USERNAME_FIELD)

        # The `username` field is allows to contain `@` characters so
        # technically a given email address could be present in either field,
        # possibly even for different users, so we'll query for all matching
        # records and test each one.
        users = user_model._default_manager.filter(
            Q(**{user_model.USERNAME_FIELD: username}) | Q(email__iexact=username)
        )

        # Test whether any matched user has the provided password:
        for user in users:
            if user.check_password(password):
                return user
        if not users:
            # Run the default password hasher once to reduce the timing
            # difference between an existing and a non-existing user (see
            # https://code.djangoproject.com/ticket/20760)
            user_model().set_password(password)
  • 在 django 中对数据库中的内容进行查询时,有时需要包含多个查询条件,此时采用 Q() 方法就很方便了。Q对象 (django.db.models.Q) 可以对关键字参数进行封装,从而更好地应用多个查询。可以组合使用 &(and), (or),~(not)操作符,当一个操作符是用于两个 Q 的对象,它产生一个新的Q对象。
  • 因为在 django 中用户的密码存储在数据库中是经过加密的,如果直接用 password==password 来进行验证是不对的。通过 user.check_password(password) 方法来进行验证密码是否正确。

使用 Postman 进行测试

postman_test

postman_test