关于本站
1、基于Django+Bootstrap开发
2、主要发表本人的技术原创博客
3、本站于 2015-12-01 开始建站
上次开发完成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第三方登录之后,再一并挂出来。其实比较简单,再页面跳转的过程中不要丢掉这个参数即可。
杨仕航
优化之后,整体的页面加载速度变快了一些
2016-09-20 14:28 回复