django 注册、登录及第三方接口程序(4):扩展邮箱注册,登录,微博登录
1.邮箱注册
这里需要扩展User,两种解决办法,1,注册时将email字段内容赋给username,这种瞒天过海型的,另一种就是扩展user,这里介绍django1.5的扩展方法。
1.setting配置
AUTH_USER_MODEL = 'manager.MyUser' # 扩展表的位置,appname.Model, MyUser是manager app下models中的用户类
AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend', 'manager.models.CustomAuth') # 后端认证
2.model
这里包含了扩展的方法和字段,贴代码如下,不明白可以看官网详解。
#coding=utf-8
from django.conf import settings
from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser
class UserManager(BaseUserManager):
"""通过邮箱,密码创建用户"""
def create_user(self, email,username, password=None,type=None,**kwargs):
if not email:
raise ValueError(u'用户必须要有邮箱')
user = self.model(
email=UserManager.normalize_email(email),
username=username,
type=type if type else 0
)
user.set_password(password)
if kwargs:
if kwargs.get('sex', None): user.sex = kwargs['sex']
if kwargs.get('is_active', None): user.is_active=kwargs['is_active']
if kwargs.get('uid', None): user.uid=kwargs['uid']
if kwargs.get('access_token', None): user.access_token=kwargs['access_token']
if kwargs.get('url', None): user.url=kwargs['url']
if kwargs.get('desc', None): user.desc=kwargs['desc']
if kwargs.get('avatar', None): user.avatar=kwargs['avatar']
user.save(using=self._db)
return user
def create_superuser(self, email, username, password):
user = self.create_user(email,
password=password,
username=username,
)
user.is_admin = True
user.save(using=self._db)
return user
class MyUser(AbstractBaseUser):
"""扩展User"""
email = models.EmailField(verbose_name='Email', max_length=255, unique=True,db_index=True)
username = models.CharField(max_length=50, unique=True, db_index=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
type = models.IntegerField(default=0) # 类型,0本站,1微博登录
sex = models.IntegerField(default=1) # sex
uid = models.CharField(max_length=50, null=True) # weibo uid
access_token = models.CharField(max_length=100, null=True) # weibo access_token
url = models.URLField(null=True) # 个人站点
desc = models.CharField(max_length=2000, null=True) # 个人信息简介
avatar = models.CharField(max_length=500, null=True) # 头像
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
def get_full_name(self):
# The user is identified by their email address
return self.email
def get_short_name(self):
# The user is identified by their email address
return self.email
def __unicode__(self):
return self.email
def has_perm(self, perm, obj=None):
"Does the user have a specific permission?"
# Simplest possible answer: Yes, always
return True
def has_module_perms(self, app_label):
"Does the user have permissions to view the app `app_label`?"
# Simplest possible answer: Yes, always
return True
@property
def is_staff(self):
"Is the user a member of staff?"
# Simplest possible answer: All admins are staff
return self.is_admin
class Meta:
db_table = 'user'
class CustomAuth(object):
"""自定义用户验证"""
def authenticate(self, email=None, password=None):
try:
user = MyUser.objects.get(email=email)
if user.check_password(password):
return user
except MyUser.DoesNotExist:
return None
def get_user(self, user_id):
try:
user = MyUser.objects.get(pk=user_id)
if user.is_active:
return user
return None
except MyUser.DoesNotExist:
return None
这样就可以使用扩展字段了。
2.注册/登录/更改密码表单
这里不罗嗦了,看代码就行了,总贴代码唯恐管理员移除了我的博客,吐槽下,博客园后台管理编辑文章markdown方式的超级烂。
class LoginForm(forms.Form):
"""
===============================================================================
function: 表单登录类
developer: BeginMan
add-time 2014/6/3
===============================================================================
"""
email = forms.EmailField(label=u'邮箱',max_length=100,widget=forms.TextInput(
attrs={'class': 'form-control', 'placeholder': u'邮箱', 'required': '', 'autofocus': ''}
),
)
pwd = forms.CharField(label=u'密码',widget=forms.PasswordInput(
attrs={'class': 'form-control', 'placeholder': u'密码', 'required': ''}
)
)
auto_login = forms.BooleanField(label=u'记住密码',required=False,
widget=forms.CheckboxInput(attrs={'value': 1}),
)
def __init__(self, request=None, *args, **kwargs):
self.request = request
self.user_cache = None
self.auth_login = None
super(LoginForm, self).__init__(*args, **kwargs)
def clean(self):
email = self.cleaned_data.get('email')
password = self.cleaned_data.get('pwd')
auth_login = self.cleaned_data.get('auth_login', None)
if email and password:
if not MyUser.objects.filter(email=email).exists():
raise forms.ValidationError(u'该账号不存在')
self.user_cache = authenticate(email=email, password=password)
if self.user_cache is None:
raise forms.ValidationError(u'邮箱或密码错误!')
elif not self.user_cache.is_active:
raise forms.ValidationError(u'该帐号已被禁用!')
if auth_login: # 如果用户勾选了自动登录
self.auth_login = True
return self.cleaned_data
def get_user_id(self):
"""获取用户id"""
if self.user_cache:
return self.user_cache.id
return None
def get_user(self):
"""获取用户实例"""
return self.user_cache
def get_auto_login(self):
"""是否勾选了自动登录"""
return self.auth_login
def get_user_is_first(self):
"""获取用户是否是第一次登录"""
is_first = False
if self.user_cache and self.user_cache.type == -1:
is_first = True
self.user_cache.type == 0
self.user_cache.save()
return is_first
class RegisterForm(forms.Form):
"""
===============================================================================
function: 表单注册类
developer: BeginMan
add-time 2014/6/3
===============================================================================
"""
email = forms.EmailField(label=u'Email', max_length=100, widget=forms.TextInput(
attrs={'class': 'form-control', 'placeholder': u'Email', 'required': '', 'autofocus': ''}
),
)
pwd = forms.CharField(label=u'密码',widget=forms.PasswordInput(
attrs={'class': 'form-control', 'placeholder': u'密码', 'required': ''}
)
)
pwd2 = forms.CharField(label=u'密码(重复)',widget=forms.PasswordInput(
attrs={'class': 'form-control', 'placeholder': u'重复密码', 'required': ''}
)
)
def __init__(self, request=None, *args, **kwargs):
self.request = request
self.user = None
super(RegisterForm, self).__init__(*args, **kwargs)
def clean(self):
data = self.cleaned_data
email = data.get('email')
pwd = data.get('pwd')
pwd2 = data.get('pwd2')
if MyUser.objects.filter(email=email).exists():
raise forms.ValidationError(u'该邮箱已被注册')
if pwd != pwd2:
raise forms.ValidationError(u'两次输入密码不一致')
if pwd2 == pwd and len(pwd) < 6:
raise forms.ValidationError(u'密码不能小于6位')
# 用户注册
# type = -1表示首次
avatar = random.choice(range(35))
avatar = '/site_media/avatar/%s.jpg' % avatar
# 生成用户并验证
username = email.split('@')
if len(username) !=2 :
raise forms.ValidationError(u'邮箱格式不对')
else:
username = ValidUs(username[0])
self.user = MyUser.objects.create_user(email=email, username=username, password=pwd, type=-1, avatar=avatar).id
return data
def get_user(self):
"""获取用户实例"""
return self.user
class PasswordForm(forms.Form):
"""
===============================================================================
function: 用户修改密码
developer: BeginMan
add-time 2014/6/3
===============================================================================
"""
oldpwd = forms.CharField(label=u'原始密码', widget=forms.PasswordInput(
attrs={'class': 'form-control', 'placeholder': u'原始密码', 'required': ''})
)
password1 = forms.CharField(label=u'新密码', widget=forms.PasswordInput(
attrs={'class': 'form-control', 'placeholder': u'密码长度在5-12位', 'required': ''})
)
password2 = forms.CharField(label=u'在输入一次', widget=forms.PasswordInput(
attrs={'class': 'form-control', 'placeholder': u'在输入一次', 'required': ''})
)
def __init__(self, user=None, *args, **kwargs):
self.user = user
self.newpwd = None
super(PasswordForm, self).__init__(*args, **kwargs)
def clean(self):
cleaned_data = super(PasswordForm, self).clean()
oldpwd = cleaned_data.get("oldpwd")
password1 = cleaned_data.get("password1")
password2 = cleaned_data.get("password2")
if not self.user.check_password(oldpwd):
msg = u"原密码错误。"
self._errors["oldpwd"] = self.error_class([msg])
# raise forms.ValidationError(u'原密码错误')
if password1 and password2:
if password1 != password2:
msg = u"两个密码字段不一致。"
self._errors["password2"] = self.error_class([msg])
if not 4 < len(password1) < 13:
msg = u"密码要在5-12位之间。"
self._errors["password1"] = self.error_class([msg])
return cleaned_data
class AvatarForm(forms.Form):
"""
===============================================================================
function: 用户修改头像
developer: BeginMan
add-time 2014/6/3
===============================================================================
"""
avatar = forms.ImageField(label=u'图片上传', widget=forms.FileInput(
attrs={'class': 'form-control', 'placeholder': u'图片上传', 'required': ''})
)
def clean(self):
cleaned_data = super(AvatarForm, self).clean()
image = cleaned_data.get("avatar", None)
if image:
if image.content_type not in ['image/jpeg', 'image/png']:
raise forms.ValidationError(u'你上传的是图片吗?')
else:
img = Image.open(image)
w, h = img.size
max_width = max_height = 1000
if w >= max_width or h >= max_height:
raise forms.ValidationError(u'上传的图片要尺寸要小于或等于%s宽,%s高' % (max_width, max_height))
if img.format.lower() not in ['jpeg', 'pjpeg', 'png', 'jpg']:
raise forms.ValidationError(u'暂时只接纳JPEG or PNG.')
#validate file size
if len(image) > (1 * 1024 * 1024):
raise forms.ValidationError('Image file too large ( maximum 1mb )')
else:
raise forms.ValidationError(u'额,图片呢?')
return cleaned_data
3.微博登录
如果你的网站想接入微博登录,那么先看看新浪开发者平台上的python SDK,API等,这里提供自己的处理方式,还是贴代码。。
首先配置的东西如key等,建议放在settings中,如下:
# 微博登陆
URL = 'http://codetheme.sinaapp.com'
APP_KEY = '你的'
APP_SERCET = '你的'
CALLBACK_URL = URL+'/login/weibo_check/' # 回调地址
url路由就自己写吧,这里给出视图方法,
def weiboLogin(request):
"""微博登录"""
client = APIClient(app_key=settings.APP_KEY, app_secret=settings.APP_SERCET, redirect_uri=settings.CALLBACK_URL)
url = client.get_authorize_url()
return HttpResponseRedirect(url)
def weibo_check(request):
code = request.GET.get('code', None)
now = datetime.datetime.now()
if code:
client = APIClient(app_key=settings.APP_KEY, app_secret=settings.APP_SERCET, redirect_uri=settings.CALLBACK_URL)
r = client.request_access_token(code)
access_token = r.access_token # 返回的token,类似abc123xyz456
expires_in = r.expires_in # token过期的UNIX时间:http://zh.wikipedia.org/wiki/UNIX%E6%97%B6%E9%97%B4
uid = r.uid
# 在此可保存access token
client.set_access_token(access_token, expires_in)
request.session['access_token'] = access_token
request.session['expires_in'] = expires_in
request.session['uid'] = uid
user = SupserWeibo(access_token=access_token, uid=uid, request=request) # 实例化超级微博类
# 更新数据库
if MyUser.objects.filter(uid=uid).exists():
MyUser.objects.filter(uid=uid).update(last_login=now)
user.Login() # 登陆
return HttpResponseRedirect('/')
else:
# 创建用户并登陆
u_id = user.createUser()
if u_id:
return HttpResponseRedirect('/manage/user/%s/' %u_id)
return HttpResponse('/404/')
这里自己写了个微博类,用于处理微博登录的基础数据,感兴趣的也可以看看,
#coding=utf-8
"""
==================================
function: 基于新浪微博API,对微博登陆进行扩展
addDate: 2014-06-04
author: BeginMan
==================================
"""
from django.conf import settings
import urllib
import urllib2
import simplejson as json
from manager.models import MyUser
from django.contrib.auth import authenticate, login, logout
from django.http import HttpResponseRedirect
import datetime
# 默认图片
DEFAULT_PIC = 'http://images.cnitblog.com/news/66372/201405/271116202595556.jpg'
# 用户信息
USER_INFO_URL = 'https://api.weibo.com/2/users/show.json'
# 发送微博
SEND_WEIBO_URL = 'https://api.weibo.com/2/statuses/upload_url_text.json'
user_agent = 'Mozilla/5.0 (Windows NT 6.1; rv:28.0) Gecko/20100101 Firefox/28.0'
headers = {'User-Agent': user_agent}
class SupserWeibo(object):
def __init__(self, access_token, uid, request=None, **kwargs):
self.access_token = access_token
self.uid = uid
self.request = request
self.user_cache = None
self.kwargs = kwargs
def createUser(self):
"""创建用户"""
userInfo = self.getUserInfo()
username=userInfo.get('screen_name')
if MyUser.objects.filter(username=username).exists():
username = username+'[weibo]'
u_id = 0
try:
new_user = MyUser.objects.create_user(
email=str(self.uid) + '@weibo.com',
username=username,
password=self.uid,
type=1,
sex=int(userInfo.get('sex', 1)),
uid=self.uid,
access_token=self.access_token,
url=userInfo.get('url', ''),
desc =userInfo.get('description', ''),
avatar=userInfo.get('avatar_large')
)
u_id = new_user.id
except:
pass
self.Login() # 登陆
return u_id
def getUserInfo(self):
"""获取微博用户信息"""
data = {'access_token': self.access_token, 'uid': self.uid}
params = urllib.urlencode(data)
values = urllib2.Request(USER_INFO_URL+'?%s' %params, headers=headers)
response = urllib2.urlopen(values)
result = json.loads(response.read())
if result.get('error_code', None):
# 写入日志
print '获取用户信息失败'
return False
return result
def SendWeibo(self):
"""用户发送微博"""
status = self.kwargs.get('status', None) # 微博内容
visible = self.kwargs.get('visible', 0) # 微博的可见性,0:所有人能看,1:仅自己可见,2:密友可见,3:指定分组可见,默认为0。
url = self.kwargs.get('url', DEFAULT_PIC) # 配图
result = {}
if status:
data = {'access_token': self.access_token, 'status': status, 'visible':visible, 'url':url}
params = urllib.urlencode(data)
values = urllib2.Request(USER_INFO_URL+'?%s' %params, headers=headers)
response = urllib2.urlopen(values)
result = json.loads(response.read())
if result.get('error_code', None):
# 写入日志
print '发送微博失败'
return False
return True
return result
def Login(self):
"""登陆"""
user_ = MyUser.objects.filter(uid=self.uid)[0]
user = authenticate(email=user_.email, password=self.uid)
login(self.request, user)
如果感兴趣,可以看看最近用django写的这个社区网站吧,基于bootstrap http://codetheme.sinaapp.com/, 源码开发了。
(网站未审核,微博登录只能供内测账号使用。)
django 注册、登录及第三方接口程序(4):扩展邮箱注册,登录,微博登录的更多相关文章
- 如何本地测试例如QQ登录等第三方接口
前言:现在基本是个网站就会集成第三方的一些接口,比如QQ登录.分享等等.但是在开发的时候,尤其是没有这方面经验的开发人员来说,调试流程时会显得迷茫,不知道怎么调试.这里就个人的这方面学习摸索做一个总结 ...
- 跟我一起学.NetCore之日志作用域及第三方日志框架扩展
前言 上一节对日志的部分核心类型进行简单的剖析,相信现在再使用日志的时候,应该大概知道怎么一回事了,比如记录器是怎么来的,是如何将日志内容写入到不同目的地的等:当然还有很多细节没深入讲解,抽时间小伙伴 ...
- dedecms织梦第三方登录插件-QQ登录、微博登录、微信登录
织梦程序集成第三方QQ登录.微博登录.微信登录,获取QQ.微博.微信,并存储至数据库,一键注册为网站会员,不用再次填写绑定信息,方便粘贴用户更强. 织梦第三方登录效果 第三方登录插件特点 1.所有文件 ...
- CocoaPods的安装及使用/利用开源库Diplomat实现分享及第三方登录/git的使用
<<史上最简洁版本>> 1.gem sources -l查看 当前的源 //1.1 sudo -i..以下都是以管理员的身份来操作的 2.gem sources --remov ...
- OAuth及第三方登录
现在的生活中运用互联网的有好多地方,我们既要申请微博,申请博客,申请邮箱等等:哪怕登录一个小网址看点东西都要注册登录,不过现在好多了:有了第三方登录,再也不用担心这不够用的脑子整天记忆账号和密码了,只 ...
- OpenID 和 OAuth 的区别及第三方登录的安全隐患分析
转自:http://itindex.net/detail/48552-openid-oauth-%E6%96%B9%E7%99%BB 发表时间:2014-03-13 19:09 | 作者:天梯梦 出处 ...
- python常用框架及第三方库
python常用框架及第三方库 一.Web框架 1.Django: 开源web开发框架,它鼓励快速开发,并遵循MVC设计,比较庞大,开发周期短.Django的文档最完善.市场占有率最高.招聘职位最多. ...
- C/S架构程序多种类服务器之间实现单点登录(转)
(一) 在项目开发的过程中,经常会出现这样的情况:我们的产品包括很多,以QQ举例,如登陆.好友下载.群下载.网络硬盘.QQ游戏.QQ音乐等,总不能要求用户每次输入用户名.密码吧,为解决这个问题,高手提 ...
- javascript取得机器名,用户名,读写注册表,启动应用程序
javascript取得机器名,用户名,读写注册表,启动应用程序//javascript有个特殊的对象ActiveXObject,通过它可以访问windows的本地文件系统和应用程序,比如:有的时候我 ...
随机推荐
- oracle中的数据对象
oracle中的数据对象有表.视图.索引.序列等 表的相关操作 1.创建表 方式一: 方式二:create table person( create table person1 id number(1 ...
- yii2.0 Cache缓存
1.控制器中CacheDemoController.php 1 <?php 2 /** 3 * Created by PhpStorm. 4 * User: liangzi 5 * Date: ...
- [转载] 散列表(Hash Table)从理论到实用(中)
转载自:白话算法(6) 散列表(Hash Table)从理论到实用(中) 不用链接法,还有别的方法能处理碰撞吗?扪心自问,我不敢问这个问题.链接法如此的自然.直接,以至于我不敢相信还有别的(甚至是更好 ...
- unreal3对象属性自动从配置文件中加载的机制
unrealscript中有两个与属性自动配置相关的关键字: config/globalconfig 当把它们应用于属性时,对象在创建后,该属性的初始值会被自动设置为相对应ini文件中的值. 举例来说 ...
- c#控制IE浏览器自动点击等事件WebBrowser,mshtml.IHTMLDocument2 .
// c#控制IE浏览器自动点击等事件WebBrowser,mshtml.IHTMLDocument2 分类: c# 2013-02-06 15:18 3008人阅读 评论(0) 收藏 举报 可以实现 ...
- treeMap and treeSet
TreeSet:如果要对对象进行排序,对象类要实现Comparable接口! TreeMap:如果要对对象进行排序,对象类要实现Comparable接口! 下面是我自己写的小程序主要传输对象 publ ...
- Java 第六章 循环结构2
循环结构 2 会使用 for 循环结构 会在程序中使用 break 和 continue for 比 while 更简洁 什么是 for 循环 ... 语法: for 循环的语法和执行顺序 备注:2条 ...
- 纯css径向渐变(CSS3--Gradient)
渐变 一.CSS3的径向渐变 效果图网址:http://www.spritecow.com 图像拼接技术 CSS3 Gradient分为linear-gradient(线性渐变)和radial-gra ...
- mfc/格式转换
1.int型转为字符串型 int s = 123; CString str; str.Format("%d",s);
- 百度上传工具webuploader,图片上传附加参数
项目中需要上传视频,图片等资源.最先做的是上传图片,开始在网上找了一款野鸡插件,可以实现图片上传预览(无需传到后台).但是最近这个插件出了莫名的问题,不易修复,一怒之下,还是决定找个大点的,靠谱的插件 ...