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):扩展邮箱注册,登录,微博登录的更多相关文章

  1. 如何本地测试例如QQ登录等第三方接口

    前言:现在基本是个网站就会集成第三方的一些接口,比如QQ登录.分享等等.但是在开发的时候,尤其是没有这方面经验的开发人员来说,调试流程时会显得迷茫,不知道怎么调试.这里就个人的这方面学习摸索做一个总结 ...

  2. 跟我一起学.NetCore之日志作用域及第三方日志框架扩展

    前言 上一节对日志的部分核心类型进行简单的剖析,相信现在再使用日志的时候,应该大概知道怎么一回事了,比如记录器是怎么来的,是如何将日志内容写入到不同目的地的等:当然还有很多细节没深入讲解,抽时间小伙伴 ...

  3. dedecms织梦第三方登录插件-QQ登录、微博登录、微信登录

    织梦程序集成第三方QQ登录.微博登录.微信登录,获取QQ.微博.微信,并存储至数据库,一键注册为网站会员,不用再次填写绑定信息,方便粘贴用户更强. 织梦第三方登录效果 第三方登录插件特点 1.所有文件 ...

  4. CocoaPods的安装及使用/利用开源库Diplomat实现分享及第三方登录/git的使用

    <<史上最简洁版本>> 1.gem sources -l查看 当前的源 //1.1 sudo -i..以下都是以管理员的身份来操作的 2.gem sources --remov ...

  5. OAuth及第三方登录

    现在的生活中运用互联网的有好多地方,我们既要申请微博,申请博客,申请邮箱等等:哪怕登录一个小网址看点东西都要注册登录,不过现在好多了:有了第三方登录,再也不用担心这不够用的脑子整天记忆账号和密码了,只 ...

  6. OpenID 和 OAuth 的区别及第三方登录的安全隐患分析

    转自:http://itindex.net/detail/48552-openid-oauth-%E6%96%B9%E7%99%BB 发表时间:2014-03-13 19:09 | 作者:天梯梦 出处 ...

  7. python常用框架及第三方库

    python常用框架及第三方库 一.Web框架 1.Django: 开源web开发框架,它鼓励快速开发,并遵循MVC设计,比较庞大,开发周期短.Django的文档最完善.市场占有率最高.招聘职位最多. ...

  8. C/S架构程序多种类服务器之间实现单点登录(转)

    (一) 在项目开发的过程中,经常会出现这样的情况:我们的产品包括很多,以QQ举例,如登陆.好友下载.群下载.网络硬盘.QQ游戏.QQ音乐等,总不能要求用户每次输入用户名.密码吧,为解决这个问题,高手提 ...

  9. javascript取得机器名,用户名,读写注册表,启动应用程序

    javascript取得机器名,用户名,读写注册表,启动应用程序//javascript有个特殊的对象ActiveXObject,通过它可以访问windows的本地文件系统和应用程序,比如:有的时候我 ...

随机推荐

  1. oracle中的数据对象

    oracle中的数据对象有表.视图.索引.序列等 表的相关操作 1.创建表 方式一: 方式二:create table person( create table person1 id number(1 ...

  2. yii2.0 Cache缓存

    1.控制器中CacheDemoController.php 1 <?php 2 /** 3 * Created by PhpStorm. 4 * User: liangzi 5 * Date: ...

  3. [转载] 散列表(Hash Table)从理论到实用(中)

    转载自:白话算法(6) 散列表(Hash Table)从理论到实用(中) 不用链接法,还有别的方法能处理碰撞吗?扪心自问,我不敢问这个问题.链接法如此的自然.直接,以至于我不敢相信还有别的(甚至是更好 ...

  4. unreal3对象属性自动从配置文件中加载的机制

    unrealscript中有两个与属性自动配置相关的关键字: config/globalconfig 当把它们应用于属性时,对象在创建后,该属性的初始值会被自动设置为相对应ini文件中的值. 举例来说 ...

  5. c#控制IE浏览器自动点击等事件WebBrowser,mshtml.IHTMLDocument2 .

    // c#控制IE浏览器自动点击等事件WebBrowser,mshtml.IHTMLDocument2 分类: c# 2013-02-06 15:18 3008人阅读 评论(0) 收藏 举报 可以实现 ...

  6. treeMap and treeSet

    TreeSet:如果要对对象进行排序,对象类要实现Comparable接口! TreeMap:如果要对对象进行排序,对象类要实现Comparable接口! 下面是我自己写的小程序主要传输对象 publ ...

  7. Java 第六章 循环结构2

    循环结构 2 会使用 for 循环结构 会在程序中使用 break 和 continue for 比 while 更简洁 什么是 for 循环 ... 语法: for 循环的语法和执行顺序 备注:2条 ...

  8. 纯css径向渐变(CSS3--Gradient)

    渐变 一.CSS3的径向渐变 效果图网址:http://www.spritecow.com 图像拼接技术 CSS3 Gradient分为linear-gradient(线性渐变)和radial-gra ...

  9. mfc/格式转换

    1.int型转为字符串型 int s = 123; CString str; str.Format("%d",s);

  10. 百度上传工具webuploader,图片上传附加参数

    项目中需要上传视频,图片等资源.最先做的是上传图片,开始在网上找了一款野鸡插件,可以实现图片上传预览(无需传到后台).但是最近这个插件出了莫名的问题,不易修复,一怒之下,还是决定找个大点的,靠谱的插件 ...