zoukankan      html  css  js  c++  java
  • django用户认证系统——注销和页面跳转5

     

    当用户想切换登录账号,或者想退出登录状态时,这时候就需要注销已登录的账号。现在我们来为网站添加注销登录的功能,这个功能 Django 也已经为我们提供,我们只需做一点简单配置。

    注销登录

    注销登录的视图为 logout,我们简单修改一下 index.html 的代码,添加一个注销登录的按钮:

    templates/index.html
    
    {% if user.is_authenticated %}
      <p>你已登录,欢迎你:<a href="#">{{ user.username }}</a></p>
      <button class="btn btn-default"><a href="{% url 'logout' %}">注销登录</a></button>
    {% else %}
      <p>你还没有登录,请
        <button class="btn btn-default"><a href="{% url 'login' %}">登录</a></button>
        或者
        <button class="btn btn-default"><a href="{% url 'users:register' %}">注册</a></button>
      </p>
    {% endif %}
    

    如果你已经登陆,就会看到一个注销登录的按钮,点击该按钮就会跳转到注销登录已成功地页面。再一次访问首页,你将看到登录、注册按钮,说明你已经成功注销登录状态了。

    页面跳转

    我们之前在登录、注册和注销的过程中发现,登录成功后会跳转到一个 404 页面,注册成功后返回的是首页,而注销登录后跳转到了 Admin 后台的注销成功页面。对于一个网站来说,比较好的用户体验是登录、注册和注销后跳转回用户之前访问的页面。否则用户在你的网站东跳转西跳转好不容易找到了想看的内容,结果他已登录给他跳转回了首页,这会使用户非常愤怒(我在有些网站就遇到过)。接下来我们看看如何让登录、注册和注销后跳转回用户之前访问的页面。

    登录和注销后返回当前页面

    在登录和注销的视图函数中,Django 已经为我们处理了跳转回用户之前访问页面的流程。其实现的原理是,在登录和注销的流程中,始终传递一个 next 参数记录用户之前访问页面的 URL。因此,我们需要做的就是在用户访问登录或者注销的页面时,在 URL 中传递一个 next 参数给视图函数,具体做法如下:

    templates/index.html
    
    <button class="btn btn-default">
      <a href="{% url 'logout' %}?next={{ request.path }}">注销登录</a>
    </button>
    
    <button class="btn btn-default">
      <a href="{% url 'login' %}?next={{ request.path }}">登录</a>
    </button>
    

    可以看到,我们在登录和注销的 URL 后加了 next 参数,其值为 {{ request.path }}。request.path 是用户当前访问页面的 URL。在 URL 中传递参数的方法就是在要传递的参数前加一个 ?然后写上传递的参数名和参数值,用等号链接。关于在 URL 中传递参数具体请 HTTP 的相关协议。

    为了在整个登录流程中记录 next 的值,还需要在登录表单中增加一个表单控件,用于传递 next 值。

    registration/login.html
    
    <form class="form" action="{% url 'login' %}" method="post">
      ...                 
      <button type="submit" class="btn btn-primary btn-block">登录</button>
      <input type="hidden" name="next" value="{{ next }}"/>
    </form>
    

    即在表单中增加了一个隐藏的 input 控件,其值为 {{ next }},即之前通过 URL 参数传递给登录视图函数的,然后登录视图函数又将该值传递给了 login.html 模板。这样在整个登录流程中,始终有一个记录着用户在登录前页面 URL 的变量 next 在视图和模板间来回传递,知道用户登录成功后再跳转回 next 记录的页面 URL。

    现在你可以点击登录和注销的按钮来走一遍登录和注销流程,发现页面跳转已经符合我们的需求了。不过还由一点点小瑕疵,就是如果用户不是通过点击登录和注销按钮,而是直接在页面输入 URL 来访问相关页面话,那这个 next 就没有值,从而无法向之前那样跳转回用户之前访问的页面。比如用户想登录,他直接在浏览器的地址栏输入 /users/login/,由于在 URL 中没有传递 next,所以就无法记录用户登录前的页面 URL,那在登录成功后就无法将他带回登录前的页面了。当然这种情况是极为罕见的,很少有用户会记住你网站的 URL 地址,但如果真有这样的用户,我们就把他跳转回首页吧,因为没有任何办法记录他之前访问的页面。要想把用户跳转回首页,可以在 settings 中做如下设置:

    LOGOUT_REDIRECT_URL = '/'
    LOGIN_REDIRECT_URL = '/'
    

    这样,整个登录和注销流程就形成了一个闭环。如果用户通过点击登录或者注销按钮登录和注销的话,在登录或者注销成功后就会被带回登录或者注销前的页面,否则将他带回网站首页。

    注册后返回当前页面

    类似的,我们也希望用户注册后返回注册前页面。不过由于注册视图函数是我们自己写的,之前的处理方式是用户注册成功后将其带回网站首页,因此需要修改一下注册视图函数:

    users/views.py
    
    def register(request):
        # 从 get 或者 post 请求中获取 next 参数值
        # get 请求中,next 通过 url 传递,即 /?next=value
        # post 请求中,next 通过表单传递,即 <input type="hidden" name="next" value="{{ next }}"/>
        redirect_to = request.POST.get('next', request.GET.get('next', ''))
    
        # 只有当请求为 POST 时,才表示用户提交了注册信息
        if request.method == 'POST':
            # request.POST 是一个类字典数据结构,记录了用户提交的注册信息
            # 这里提交的就是用户名(username)、密码(password)、确认密码、邮箱(email)
            # 用这些数据实例化一个用户注册表单
            form = RegisterForm(request.POST)
    
            # 验证数据的合法性
            if form.is_valid():
                # 如果提交数据合法,调用表单的 save 方法将用户数据保存到数据库
                form.save()
    
                if redirect_to:
                    return redirect(redirect_to)
                else:
                    return redirect('/')
        else:
            # 请求不是 POST,表明用户正在访问注册页面,展示一个空的注册表单给用户
            form = RegisterForm()
    
        # 渲染模板
        # 如果用户正在访问注册页面,则渲染的是一个空的注册表单
        # 如果用户通过表单提交注册信息,但是数据验证不合法,则渲染的是一个带有错误信息的表单
        # 将记录用户注册前页面的 redirect_to 传给模板,以维持 next 参数在整个注册流程中的传递
        return render(request, 'users/register.html', context={'form': form, 'next': redirect_to})
    

    逻辑非常简答,就是首先尝试从用户的 GET 或者 POST 请求中获取 next 参数值,即在注册成功后需要跳转的 URL,如果有值,注册成功后跳转到该 URL,否则跳转回首页。同是不要忘记将该值传给模板,以维持 next 参数在整个注册流程中的传递。

    接下来修改模板,和登录模板的设置是一样的:

    registration/login.html
    
    <button class="btn btn-default">
      <a href="{% url 'users:register' %}?next={{ request.path }}">注册</a>
    </button>
    
    templates/users/register.html
    
    <form class="form" action="{% url 'users:register' %}" method="post">
      ...       
      <button type="submit" class="btn btn-primary btn-block">注册</button>
      <input type="hidden" name="next" value="{{ next }}"/>
    </form>
    

    注意:在注册视图函数中,对 next 的任意值我们都进行了跳转,这可能导致一些安全问题。正确的做法应该是在跳转前,对需要跳转的 URL 做安全性检查。不过这里只作为一个示例,在实际项目中请仔细考虑可能的安全后果,以及添加必要的安全性检查代码。

    OK,如此修改以后,用户的登录、注册和注销流程的用户体验可以形成一个比较良好闭环了。接下来就来实现修改密码的功能。

  • 相关阅读:
    如何使用SAP Intelligent Robotic Process Automation自动操作Excel
    OpenSAML 使用引导 IV: 安全特性
    Spring Cloud Zuul 网关使用与 OAuth2.0 认证授权服务
    微服务架构集大成者—Spring Cloud (转载)
    Spring Cloud Eureka 服务注册列表显示 IP 配置问题
    使用 Notification API 开启浏览器桌面提醒
    SignalR 中使用 MessagePack 序列化提高 WebSocket 通信性能
    配置 Nginx 的目录浏览功能
    关于 Nginx 配置 WebSocket 400 问题
    Migrate from ASP.NET Core 2.0 to 2.1
  • 原文地址:https://www.cnblogs.com/AmilyWilly/p/8469865.html
Copyright © 2011-2022 走看看