我正在使用 python-social-auth 和 django-rest-framework 来允许用户在我的应用程序中使用他们的社交帐户进行注册。
我的情况类似于这篇文章 用户不是在使用 facebook 登录后创建的(可能是同名案例)
我使用 django-rest-framework 的 TokenAuthentication 对用户进行身份验证
使用我的自定义用户模型时,当标头中有可用的 authtoken(用户已登录)时,创建的社交用户帐户将链接到其令牌按预期附加到请求的用户,但是当没有可用的令牌时,它无法创建新帐户。
但是当使用默认的 django 用户模型时,一切都按预期工作。我怀疑我没有正确配置我的自定义用户模型。
下面是我的设置文件,你可以看看,看看你能不能找出我做错了什么。
提前致谢。
我的设置文件
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticatedOrReadOnly',
),
'PAGINATE_BY': 10
}
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
'django.core.context_processors.static',
'django.core.context_processors.tz',
'django.contrib.messages.context_processors.messages',
'django.core.context_processors.request',
'social.apps.django_app.context_processors.backends',
)
SOCIAL_AUTH_FACEBOOK_KEY = os.environ.get('FB_APP_ID')
SOCIAL_AUTH_FACEBOOK_SECRET = os.environ.get('FB_APP_SECRET')
SOCIAL_AUTH_FACEBOOK_EXTENDED_PERMISSIONS = ['email']
SOCIAL_AUTH_FACEBOOK_SCOPE = ['email']
SOCIAL_AUTH_USER_MODEL = 'users.FLUser'
SOCIAL_AUTH_TWITTER_KEY = os.environ.get('TWITTER_APP_ID')
SOCIAL_AUTH_TWITTER_SECRET = os.environ.get('TWITTER_APP_SECRET')
AUTHENTICATION_BACKENDS = (
'social.backends.twitter.TwitterOAuth',
'social.backends.facebook.FacebookOAuth2',
'social.backends.facebook.Facebook2OAuth2',
'django.contrib.auth.backends.ModelBackend',
)
SOCIAL_AUTH_PIPELINE = (
'social.pipeline.social_auth.social_details',
'social.pipeline.social_auth.social_uid',
'social.pipeline.social_auth.auth_allowed',
'social.pipeline.social_auth.social_user',
'social.pipeline.user.get_username',
'social.pipeline.social_auth.associate_by_email',
'social.pipeline.user.create_user',
'social.pipeline.social_auth.associate_user',
'social.pipeline.social_auth.load_extra_data',
'social.pipeline.user.user_details'
# 'apps.users.pipeline.user_details',
)
定制经理
class FLUserManager(BaseUserManager):
def _create_user(self, username, email, password,
is_staff, is_superuser, **extra_fields):
"""
Creates and saves a User with the given username, email and password.
"""
now = timezone.now()
if not email:
raise ValueError('The given username must be set')
email = self.normalize_email(email)
user = self.model(username=username, email=email,
is_staff=is_staff, is_active=True,
is_superuser=is_superuser, last_login=now,
date_joined=now, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, username, email=None, password=None, **extra_fields):
return self._create_user(username, email, password, False, False,
**extra_fields)
def create_superuser(self, username, email, password, **extra_fields):
return self._create_user(username, email, password, True, True,
**extra_fields)
自定义用户模型
class FLUser(AbstractBaseUser, PermissionsMixin):
GENDER = (
('M', 'Male'),
('F', 'Female'),
)
email = models.EmailField(
verbose_name=_('email address'),
max_length=255,
unique=True,
)
username = models.CharField(
verbose_name=_('username'),
max_length=30,
unique=False,
help_text=_('Required. 30 characters or fewer. Letters, numbers and '
'@/./+/-/_ characters'),
validators=[
validators.RegexValidator(re.compile('^[\w.@+-]+$'),
_('Enter a valid username.'), 'invalid')
]
)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
birthday = models.DateTimeField(
blank=True,
default=None,
null=True
)
gender = models.CharField(
max_length=1,
choices=GENDER,
default=None,
null=True
)
avatar = models.ImageField(
upload_to='media/avatars',
blank=True,
default=None,
null=True
)
sm_avatar = models.URLField(
blank=True,
default=None,
null=True,
verbose_name=_('Social Media Avatar')
)
is_active = models.BooleanField(
_('active'),
default=True,
help_text=_('Designates whether this user should be treated as '
'active. Unselect this instead of deleting accounts.')
)
is_admin = models.BooleanField(default=False)
objects = FLUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name', 'username',]
def is_authenticated(self):
return True
def get_full_name(self):
return '''{} {}'''.format(self.first_name, self.last_name)
def get_short_name(self):
return self.first_name
@property
def is_staff(self):
return self.is_admin
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
# On Python 3: def __str__(self):
def __unicode__(self):
return self.email
def email_user(self, subject, message, from_email=None):
"""
Sends an email to this User.
"""
send_mail(subject, message, from_email, [self.email])
class Meta:
ordering = ('id', 'first_name',)
verbose_name = _('user')
verbose_name_plural = _('users')
@receiver(post_save, sender=FLUser)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if created:
Token.objects.create(user=instance)
风景
@api_view(['POST'])
@permission_classes((AllowAny,))
@strategy()
def register_by_access_token(request, backend):
backend = request.strategy.backend
if backend.name == 'twitter':
token = {
'oauth_token': request.DATA.get('access_token'),
'oauth_token_secret': os.environ.get('TWITTER_APP_OAUTH_SECRET'),
}
elif backend.name == 'facebook':
token = request.POST.get('access_token')
else:
raise Response('Wrong backend type', status=HTTP_400_BAD_REQUEST)
user = backend.do_auth(
access_token=token,
user=request.user.is_authenticated() and request.user or None
)
if user and user.is_active:
login(request, user)
user = UserAuthSerializer(user)
return Response(user.data, status=HTTP_200_OK)
else:
return Response({'detail': 'Unable to authenticate user'}, status=HTTP_400_BAD_REQUEST)