我的网站搭建(第31天) 优化登录和注册页面

  • 发布时间:2016年9月20日 14:26
  • 作者:杨仕航
* 该文是基于Python2.7开发的,最新Python3.x和Django2.x视频教程可以前往 >> Django2.0视频教程

上次开发完成Github第三方登录之后,接下来需要整理一下3个第三方账号登录的代码。

但发现现有的登录和注册的代码影响到OAuth第三方登录代码整理,需要对登录和注册的代码进行优化。

之前写的登录、注册为了图方便就利用了Bootstrap的模态框。在最底层的模版页面加了两个form,以及对这两个form的ajax提交写了不少的js代码。具体可以参考前面写的登入登出相关博文。

这样处理看上去是方便,每次登录之后直接刷新页面即可,不用重新跳转定位到未登录之前的页面。

而且页面也好看:

这么处理也造成两个问题:

1)由于这些代码都是写在最底层的模版页中,导致每个页面的代码量比较多;

2)由于写在最底层的模版页中,也导致没办法给每个请求返回最新的crsf码,导致登录和注册没有crsf保护。


综上所述,所以需要对登录/注册该部分的功能进行优化。

初步优化方案:登录和注册使用同一个form表单,减少代码冗余。另外所有的登录和注册行为都跳转到这个form表单页面中,不再写在最底层的模版中,减少每个页面的html代码。这个方案可以充分优化该功能。

重点还需要解决一个问题:登录或注册之后,重新跳转回点击登录或注册之前的页面


统计了一下,一共有4个地方需要跳转处理:

1)使用我的网站账号登录之后的跳转;

2)在我的网站直接注册之后的跳转;

3)使用第三方账号登录之后的跳转;

4)初次使用第三方账号登录,绑定用户之后的跳转。


这4种情况可以归纳为两种类型:我的网站账号和第三方账号登录。

一开始请求打开登录或注册的页面时,可以利用 referrer = request.META.get('HTTP_REFERER','/') 得到跳转之前的页面地址。

再把这个地址当作OAuth的state参数值,这样就可以保留这个地址。登录或注册完成之后,再跳转到这个地址即可。


最后,我的登录和注册的页面做成这样的效果,如下图:

登录和注册使用到的邮箱和密码框都使用同一个表单。去掉样式,核心的html代码如下:

<form id="user_form" class="main_form" method='post'>
    {%csrf_token%}
    <input id="reback_url" type="hidden" value="{{reback_url}}">

    <span>邮箱:</span><input type="text" id="user_name" name="user_name">
    <span>密码:</span><input type="password" id="user_pwd" name="user_pwd">

    <span class="other_account">第三方账号登录:</span>
    <a href="/oauth/qq_login?state={{reback_url}}" title="QQ登录">
        <img src="/static/img/logo_qq.png" alt="QQ登录">
    </a>
    <a href="/oauth/sina_login?state={{reback_url}}" title="微博登录">
        <img src="/static/img/logo_sina.png" alt="微博登录">
    </a>
    <a href="/oauth/github_login?state={{reback_url}}" title="Github登录">
        <img src="/static/img/logo_github.png" alt="Github登录">
    </a>
    
    <p id="tip_text" style="color:red;"></p>
    
    <input type="submit" class="btn btn-primary" value="登录"/>
    <a class="btn btn-default" href="{% url 'password_lost' %}">忘记密码</a>
    
    <input id="user_reg" type="button" class="btn btn-primary" value="注册"/>
</form>

其中,{{reback_url}}是跳转进来之前页面的网址。把这个记录在一个hidden字段中。另外第三方登录的按钮都加入了state参数,用于跳转。其他的url都是我之前写的登录和注册的ajax代码。具体可以参考我之前写的用户认证博文。


这个前端页面再写ajax的代码即可,这里登录或注册成功之后,再跳转到原来的页面:

<script type="text/javascript">
    $(function(){
        //登录
        $('#user_form').submit(function(){
            //验证
            var tip=$('#tip_text');
            tip.text('');

            if($('#user_name').val()==''){
                tip.text('请输入邮箱');
                return false;
            };
            if($('#user_pwd').val()==''){
                tip.text('请输入密码');
                return false;
            };

            //登录
            $.ajax({
                type: "POST",
                data: $('#user_form').serialize(),
                url: "{% url 'user_login' %}",
                cache: false,
                dataType: "json",
                success: function(json, textStatus){
                    var is_success = json['success'];
                    if(is_success){
                        tip.text('登录成功,页面处理中...');

                        //跳转回原来的页面
                        var reback_url = $('#reback_url').val();
                        if(!reback_url){reback_url='/';}
                        window.location.href = reback_url;
                    }else{
                        tip.text('邮箱或者密码错误,请重试');
                    };
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    tip.text("登录出错,请重试 "+errorThrown);
                }
            });
            return false;
        });

        //注册
        $('#user_reg').click(function(){
            //验证
            var tip=$('#tip_text');
            tip.text('');

            var reg_name=$('#user_name').val();
            var reg_pwd=$('#user_pwd').val();

            if(reg_name==''){
                tip.text('邮箱不能为空');
                return false;
            };
            if(!reg_name.match(/^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\.[a-zA-Z0-9_-]{2,3}){1,2})$/)){
                tip.text('请输入正确的邮箱格式');
                return false;
            }

            if(reg_pwd==''){
                tip.text('密码不能为空');
                return false    ;
            };
            if(reg_pwd.length<6){
                tip.text('密码不能少于6位');
            }

            //注册
            tip.text('注册中,请稍后...');
            $.ajax({
                type: "POST",
                data: $('#user_form').serialize(),
                url: "{% url 'user_reg' %}",
                cache: false,
                dataType: "json",
                success: function(json, textStatus){
                    var is_success = json['success'];
                    if(is_success){
                        tip.text('注册成功,页面处理中...');
                        $('#user_control').text(json['message']);

                        window.setTimeout(function(){ 
                            var reback_url = $('#reback_url').val();
                            if(!reback_url){reback_url='/';}
                            window.location.href = reback_url;
                        },3000);
                    }else{
                        tip.text(json['message']);
                    };
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    tip.text("注册出错,请重试 "+errorThrown);
                }
            });
            return false;
        });
    });
</script>

另外把最底层模版页中的登录和注册按钮修改成a标签并指向这个页面。前端页面这样就可以了。

打开后台的代码,找到登录和注册对应处理代码的位置。


首先是打开这个登录页面的处理方法,通过META的HTTP_REFERER得到网址,记得添加这个页面的路由设置。

from django.shortcuts import render_to_response
from django.template import RequestContext

def login_page(request):
    """打开登录页面"""
    data = {}

    #得到跳转进来的页面
    referrer = request.META.get('HTTP_REFERER','/')
    data['reback_url'] = referrer

    return render_to_response("user/login.html", data, context_instance=RequestContext(request))

另外原本的登录和注册的处理方法,不用修改,主要注意表单的参数正确即可。


我的网站账号处理完成之后,还需要第三方账号登录之后的跳转。

之前的第三方登录代码可以参考前面的博文(内容比较多,这里就不说了。内容太多,也不方便说。)

以QQ登录为例,只需要修改参数中的state即可。

def qq_login(request):
    state = request.GET.get('state') #获取state参数
    config = settings.OAUTH_QQ_CONFIG

    if state:
        config['state'] = state #修改state参数
    oauth_qq = OAuth_QQ(config)

    #获取 得到Authorization Code的地址
    url = oauth_qq.get_auth_url()
    return HttpResponseRedirect(url)

这样,QQ服务器认证通过之后,就会把state原封不动的返回回来。登录完成之后,再跳转到这个state记录的网址即可。同样,中途若需要打开绑定的用户的页面时,只需要把这个state参数传递过去即可。

完整的代码,等我优化整理OAuth第三方登录之后,再一并挂出来。其实比较简单,再页面跳转的过程中不要丢掉这个参数即可。

上一篇:如何解决Excel文件变大的问题

下一篇:我的网站搭建(第30天) 第三方登录:Github

评论列表

杨仕航

杨仕航

优化之后,整体的页面加载速度变快了一些

2016-09-20 14:28 回复

新的评论

清空