Django 自定义用户认证

Django 自带的 admin 提供了方便,如果要重写该怎么实现?如下:

1. 如果想实现自定义 User,加一个 app,如名为 auth2。在此 app 中加 用户 Model:

class User(AbstractBaseUser, PermissionsMixin):
    '''继承 AbstractBaseUser 和 PermissionsMixin 可以重用认证必需的属性和方法,也可以完全重写'''
    username = models.CharField(u'User Name', max_length=30, unique=True)
    mobile = models.CharField(u'Mobile', max_length=11, blank=True)
    email = models.EmailField(u'Email address', blank=True)
    is_staff = models.BooleanField(u'staff status', default=False)
    is_active = models.BooleanField(u'active', default=True)

    date_joined = models.DateTimeField(u'date joined', default=timezone.now)  # 如果用 Django 自带的 UserManager(见下面代码) 则必须,否则可不用

    USERNAME_FIELD = 'username'  # 指定代表用户名的字段名
    REQUIRED_FIELDS = ['email']  # 如果用 Django 自带的 UserManager 时必须,因为其创建超级用户时必须有 email,即在syncdb 创建时要求填写
    objects = UserManager() # 用 Django 自带的 UserManager,如果定义的字段出入较大,当然需要自己实现

    def get_full_name(self):
        '''启用 Django 自带 Admin 时需实现,因为 Admin 显示用户名时需要'''
        return self.username

    def get_short_name(self):
        '''启用 Django 自带 Admin 时需实现,因为 Admin 显示用户名时需要'''
        return self.username

然后在 INSTALLED_APPS 加上 auth2,并在 settings 添加配置 AUTH_USER_MODEL

AUTH_USER_MODEL = 'auth2.User'

如果想先确认是否成功,可以 syncdb 数据库会有 auth2_user 表,让项目跑起来之后走 Admin 认证。

2. 如果想进一步定义认证机制,比如不只校验用户名密码,可以自己实现 Authentication backend,官方参考:https://docs.djangoproject.com/en/1.9/topics/auth/customizing/#writing-an-authentication-backend

3. 如果登录提交的表单不只用户名密码,自然需要重写 login 和 logout

@csrf_protect
@never_cache
def login(request, authentication_form=AuthenticationForm):  # 认证表单 AuthenticationForm  需自己实现,可参考默认认证的表单
    redirect_to = request.POST.get(REDIRECT_FIELD_NAME,
                                   request.GET.get(REDIRECT_FIELD_NAME, ''))  # 取 next 的值作为跳转页 URL

    if not is_safe_url(url=redirect_to, host=request.get_host()):
        redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL)  # 需在 settings 设置登录后默认跳转页

    if request.method == 'GET' and request.user.is_active and request.user.is_staff:  # 已登录用户跳转
        return HttpResponseRedirect(redirect_to)

    if request.method == "POST":
        form = authentication_form(request, data=request.POST)
        if form.is_valid():
            auth_login(request, form.get_user())

            return HttpResponseRedirect(redirect_to)  # 登录成功跳转
    else:
        form = authentication_form(request)

    context = {
        'form': form,
        REDIRECT_FIELD_NAME: redirect_to,
    }

    return TemplateResponse(request, 'auth2/login.html', context)

def logout(request):
    auth_logout(request)
    return HttpResponseRedirect(resolve_url('/auth2/login/'))

以上只是最简单的重写认证需要做的。既然重写,为什么这么麻烦,还需沿用部分 Django 自带功能呢?至少以上的实现可以使用 Django 原有的用户权限模块的功能,尽量不重复造轮子。