用户名登录

登录的核心思想,认证和状态放弃,通过用户的认证,确定该登录用户是美多商场的注册用户。通过状态放弃缓存用户的惟一标识信息,用于后续是否登录的判断。

1. 用户名登录逻辑剖析

2. 用户名登录接口设计

1.申请形式
选项计划
申请办法POST
申请地址/login/
2.申请参数:表单
参数名类型是否必传阐明
usernamestring用户名
passwordstring明码
rememberedstring是否记住用户
3.响应后果:HTML
字段阐明
登录失败响应谬误提醒
登录胜利重定向到首页

3. 用户名登录接口定义

class LoginView(View):    """用户名登录"""    def get(self, request):        """        提供登录界面        :param request: 申请对象        :return: 登录界面        """        pass    def post(self, request):        """        实现登录逻辑        :param request: 申请对象        :return: 登录后果        """        pass

4. 用户名登录后端逻辑

class LoginView(View):    """用户名登录"""    def get(self, request):        """        提供登录界面        :param request: 申请对象        :return: 登录界面        """        return render(request, 'login.html')    def post(self, request):        """        实现登录逻辑        :param request: 申请对象        :return: 登录后果        """        # 承受参数        username = request.POST.get('username')        password = request.POST.get('password')        remembered = request.POST.get('remembered')        # 校验参数        # 判断参数是否齐全        if not all([username, password]):            return http.HttpResponseForbidden('短少必传参数')        # 判断用户名是否是5-20个字符        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):            return http.HttpResponseForbidden('请输出正确的用户名或手机号')        # 判断明码是否是8-20个数字        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):            return http.HttpResponseForbidden('明码起码8位,最长20位')        # 认证登录用户        user = authenticate(username=username, password=password)        if user is None:            return render(request, 'login.html', {'account_errmsg': '用户名或明码谬误'})        # 实现状态放弃        login(request, user)        # 设置状态放弃的周期        if remembered != 'on':            # 没有记住用户:浏览器会话完结就过期            request.session.set_expiry(0)        else:            # 记住用户:None示意两周后过期            request.session.set_expiry(None)        # 响应登录后果        return redirect(reverse('contents:index'))

多账号登录

Django自带的用户认证零碎只会应用用户名去认证一个用户。所以咱们为了实现多账号登录,用户名、手机号或者第三方登陆,就须要自定义认证后端,采纳其余的惟一信息去认证一个用户

自定义用户认证后端步骤

  • 在users利用中新建utils.py文件
  • 新建类,继承自ModelBackend
  • 重写认证authenticate()办法
  • 别离应用用户名和手机号查问用户
  • 返回查问到的用户实例

1. 自定义用户认证后端

users.utils.py
from django.contrib.auth.backends import ModelBackendimport refrom .models import Userdef get_user_by_account(account):    """    依据account查问用户    :param account: 用户名或者手机号    :return: user    """    try:        if re.match('^1[3-9]\d{9}$', account):            # 手机号登录            user = User.objects.get(mobile=account)        else:            # 用户名登录            user = User.objects.get(username=account)    except User.DoesNotExist:        return None    else:        return userclass UsernameMobileAuthBackend(ModelBackend):    """自定义用户认证后端"""    def authenticate(self, request, username=None, password=None, **kwargs):        """        重写认证办法,实现多账号登录        :param request: 申请对象        :param username: 用户名        :param password: 明码        :param kwargs: 其余参数        :return: user        """        # 依据传入的username获取user对象。username能够是手机号也能够是账号        user = get_user_by_account(username)        # 校验user是否存在并校验明码是否正确        if user and user.check_password(password):            return user

2. 配置自定义用户认证后端

1.Django自带认证后端源码

2.配置自定义用户认证后端
# 指定自定义的用户认证后端AUTHENTICATION_BACKENDS = ['users.utils.UsernameMobileAuthBackend']

3. 测试自定义用户认证后端

首页用户名展现

1. 首页用户名展现计划

计划一

  • 模板中 request 变量间接渲染用户名
  • 毛病:不不便做首页动态化
{% if user.is_authenticated %}    <div class="login_btn fl">        欢迎您:<em>{{ user.username }}</em>        <span>|</span>        <a href="#">退出</a>    </div>    {% else %}    <div class="login_btn fl">        <a href="login.html">登录</a>        <span>|</span>        <a href="register.html">注册</a>    </div>{% endif %}

计划二

  • 发送ajax申请获取用户信息
  • 毛病:须要发送网络申请
<div class="login_btn fl">    {# ajax渲染 #}</div>

计划三

  • Vue读取cookie渲染用户信息
<div v-if="username" class="login_btn fl">    欢迎您:<em>[[ username ]]</em>    <span>|</span>    <a href="#">退出</a></div><div v-else class="login_btn fl">    <a href="login.html">登录</a>    <span>|</span>    <a href="register.html">注册</a></div>

论断:

  • 比照此三个计划,咱们在本我的项目中抉择 计划三

实现步骤:

  • 注册或登录后,用户名写入到cookie
  • Vue渲染主页用户名

2. 用户名写入到cookie

# 响应注册后果response = redirect(reverse('contents:index'))# 注册时用户名写入到cookie,有效期15天response.set_cookie('username', user.username, max_age=3600 * 24 * 15)return response# 响应登录后果response = redirect(reverse('contents:index'))# 登录时用户名写入到cookie,有效期15天response.set_cookie('username', user.username, max_age=3600 * 24 * 15)return response

3. Vue渲染首页用户名

1.index.html
<div v-if="username" class="login_btn fl">    欢迎您:<em>[[ username ]]</em>    <span>|</span>    <a href="#">退出</a></div><div v-else class="login_btn fl">    <a href="login.html">登录</a>    <span>|</span>    <a href="register.html">注册</a></div>
2.index.js
mounted(){    // 获取cookie中的用户名    this.username = getCookie('username');},

退出登录

退出登录的核心思想就是清理登录时缓存的状态放弃信息。因为首页中用户名是从cookie中读取的。所以退出登录时,须要将cookie中用户名革除。

1. logout()办法介绍

  1. 退出登录:

    • 回顾登录:将通过认证的用户的惟一标识信息,写入到以后session会话中
    • 退出登录:正好和登录相同(清理session会话信息)
  2. logout()办法:

    • Django用户认证零碎提供了logout()办法
    • 封装了清理session的操作,帮忙咱们疾速实现登出一个用户
  3. logout()地位:

    • django.contrib.auth.__init__.py文件中
logout(request)

2. logout()办法应用

class LogoutView(View):    """退出登录"""    def get(self, request):        """实现退出登录逻辑"""        # 清理session        logout(request)        # 退出登录,重定向到登录页        response = redirect(reverse('contents:index'))        # 退出登录时革除cookie中的username        response.delete_cookie('username')        return response

判断用户是否登录

1. 展现用户核心界面

class UserInfoView(View):    """用户核心"""    def get(self, request):        """提供个人信息界面"""        return render(request, 'user_center_info.html')

需要:

  • 当用户登录后,能力拜访用户核心。
  • 如果用户未登录,就不容许拜访用户核心,将用户疏导到登录界面。

实现计划:

  • 须要判断用户是否登录。
  • 依据是否登录的后果,决定用户是否能够拜访用户核心。

2. is_authenticate 判断用户是否登录

介绍:

  • Django用户认证零碎提供了办法request.user.is_authenticated()来判断用户是否登录。
  • 如果通过登录验证则返回True。反之,返回False
  • 毛病:登录验证逻辑很多中央都须要,所以该代码须要反复编码好屡次。
class UserInfoView(View):    """用户核心"""    def get(self, request):        """提供个人信息界面"""        if request.user.is_authenticated():            return render(request, 'user_center_info.html')        else:            return redirect(reverse('users:login'))

3. login_required装璜器 判断用户是否登录

  • Django用户认证零碎提供了装璜器

    login_required

来判断用户是否登录。

  • 外部封装了is_authenticate
  • 地位:django.contrib.auth.decorators
  • 如果通过登录验证则进入到视图外部,执行视图逻辑。
  • 如果未通过登录验证则被重定向到

    LOGIN_URL

配置项指定的地址。

  • 如下配置:示意当用户未通过登录验证时,将用户重定向到登录页面。

    LOGIN_URL = '/login/'

1.装璜as_view()办法返回值

提醒:

  • login_required装璜器能够间接装璜函数视图,然而本我的项目应用的是类视图。
  • as_view()办法的返回值就是将类视图转成的函数视图。

论断:

  • 要想应用login_required装璜器装璜类视图,能够间接的装璜as_view()办法的返回值,以达到预期成果。
url(r'^info/$', login_required(views.UserInfoView.as_view()), name='info'),class UserInfoView(View):    """用户核心"""    def get(self, request):        """提供个人信息界面"""        return render(request, 'user_center_info.html')

2.定义View子类封装login_required装璜器

  • 提醒:LoginRequired(object)依赖于视图类View,复用性很差。
url(r'^info/$', views.UserInfoView.as_view(), name='info'),class LoginRequired(View):  """验证用户是否登陆"""  @classmethod  def as_view(cls, **initkwargs):      # 自定义as_view()办法中,调用父类的as_view()办法      view = super().as_view()      return login_required(view)class UserInfoView(LoginRequired):    """用户核心"""    def get(self, request):        """提供个人信息界面"""        return render(request, 'user_center_info.html')

3.定义obejct子类封装login_required装璜器

  • 提醒:LoginRequired(object)不依赖于任何视图类,复用性更强。
url(r'^info/$', views.UserInfoView.as_view(), name='info'),class LoginRequired(object):  """验证用户是否登陆"""  @classmethod  def as_view(cls, **initkwargs):      # 自定义as_view()办法中,调用父类的as_view()办法      view = super().as_view()      return login_required(view)class UserInfoView(LoginRequired, View):    """用户核心"""    def get(self, request):        """提供个人信息界面"""        return render(request, 'user_center_info.html')

4.定义验证用户是否登录扩大类

  • 提醒:定义扩大类不便我的项目中导入和应用(meiduo_mall.utils.views.py)
class LoginRequiredMixin(object):  """验证用户是否登录扩大类"""  @classmethod  def as_view(cls, **initkwargs):      # 自定义的as_view()办法中,调用父类的as_view()办法      view = super().as_view()      return login_required(view) class UserInfoView(LoginRequiredMixin, View):    """用户核心"""    def get(self, request):        """提供个人信息界面"""        return render(request, 'user_center_info.html')

4. 登录时next参数的应用

1.next参数的成果
http://127.0.0.1:8000/login/?next=/info/

2.next参数的作用

  • 由Django用户认证零碎提供,搭配login_required装璜器应用。
  • 记录了用户未登录时拜访的地址信息,能够帮忙咱们实现在用户登录胜利后间接进入未登录时拜访的地址。
# 响应登录后果next = request.GET.get('next')if next:    response = redirect(next)else:    response = redirect(reverse('contents:index'))