代码之家  ›  专栏  ›  技术社区  ›  Arundeep Chohan

通过电子邮件联系用户

  •  1
  • Arundeep Chohan  · 技术社区  · 4 年前

    我想覆盖管道,将用户的帐户与他们的电子邮件关联,以获得仅处于活动状态的帐户。但我需要一个常规登录的后端。AUTHENTICATION_BACKENDS(django.contrib.auth.BACKENDS.AllowAllUsersModelBackend)允许对所有用户进行身份验证,但我只希望使用Google登录对处于活动状态的某些用户进行身份验证。

    设置。py

    AUTHENTICATION_BACKENDS = ['social_core.backends.google.GoogleOAuth2','django.contrib.auth.backends.AllowAllUsersModelBackend',]
    # Extends default user with additional fields 
    AUTH_USER_MODEL = 'pages.Profile' 
    SOCIAL_AUTH_USER_MODEL = 'pages.Profile' 
    
    # social auth configs for google
    SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = config('GOOGLE_OAUTH2_KEY')
    SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = config('GOOGLE_OAUTH2_SECRET')
    SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = ['https://www.googleapis.com/auth/calendar']
    SOCIAL_AUTH_JSONFIELD_ENABLED = True
    SOCIAL_AUTH_GOOGLE_OAUTH2_AUTH_EXTRA_ARGUMENTS = {'access_type': 'offline','approval_prompt':'force'}
    SESSION_COOKIE_SAMESITE = None
    SOCIAL_AUTH_PIPELINE = (
        'social_core.pipeline.social_auth.social_details',
        'social_core.pipeline.social_auth.social_uid',
        'social_core.pipeline.social_auth.auth_allowed',
        'social_core.pipeline.social_auth.social_user',
        'social_core.pipeline.user.get_username',
        'social_core.pipeline.social_auth.associate_by_email',  # <--- enable this one
        'social_core.pipeline.user.create_user',
        'social_core.pipeline.social_auth.associate_user',
        'social_core.pipeline.social_auth.load_extra_data',
        'social_core.pipeline.user.user_details',
        'pages.pipeline.save_token'
    ) 
    

    意见。py

    def login(request):
        if request.method == 'POST':
            form = AuthenticationForm(request.POST)
            username = request.POST['username']
            password = request.POST['password']
            user = authenticate(username=username, password=password)
            if user:
                if user.is_active:
                    auth_login(request, user)
                    return redirect('home')
                else:
                    messages.error(request,'User blocked',extra_tags='login')
                    return redirect('login')
            else:
                messages.error(request,'username or password not correct',extra_tags='login')
                return redirect('login')
        else:
            form = AuthenticationForm()
        return render(request, 'registration/login.html',{'form':form})
    
    1 回复  |  直到 4 年前
        1
  •  1
  •   dmitryro    4 年前

    要覆盖原始部分,

    在你的管道中。py (如果应用程序目录中没有,请创建一个), 定义一种方法 :

    from social_core.pipeline.partial import partial
    from social_core.exceptions import AuthAlreadyAssociated, AuthException, AuthForbidden
    
    
    @partial
    def associate_by_email(backend, details, user=None, *args, **kwargs):
        # No user 
        if user:
            return None
    
        email = details.get('email')
        if email:
            # Try to associate accounts registered with the same email address,
            # only if it's a single object. AuthException is raised if multiple
            # objects are returned.
            users = list(backend.strategy.storage.user.get_users_by_email(email))
    
            #That's the line you want to add
            active_users = [user for user in users if user.is_active]
    
            if len(active_users) == 0:
                return None
            elif len(active_users) > 1:
                    raise AuthException(
                        backend,
                        'The given email address is associated with another account'
                    )
            else:
                return {'user': active_users[0],
                        'is_new': False}
    

    然后在你的 设置。py 更换线路

    SOCIAL_AUTH_PIPELINE = (
        ...
        'social_core.pipeline.social_auth.associate_by_email',  # <--- enable this
        ...
    )
    

    与:

    SOCIAL_AUTH_PIPELINE = (
        ...
        'your_app.pipeline.associate_by_email',  # <--- enable this one
        ...
    )
    

    确保将管道部分放置在原来的位置。 原始方法不执行检查,因此要添加此行为,您必须编写自己的部分来覆盖此行为。 假设你有一个Django应用程序(为了简单起见,这里称为 你的应用 -只需相应地更新名称。 partial的原始代码 associate_by_email 可以找到 here .

    如果要将此检查添加到简单身份验证,可以在文件中提供自己的后端 你的应用程序/后端。py :

    from django.core.exceptions import ObjectDoesNotExist
    from settings import settings
    from django.contrib.auth.models import User
    from django.contrib.auth.backends import ModelBackend
    
    class LocalActiveBackend(object):
        def authenticate(self, username=None, password=None):
            try:
                # Add extra check for is_active
                user = User.objects.get(username=username, is_active=True)
            except User.DoesNotExist:
                return None
    
            pwd_valid = user.check_password(password)
        
            if pwd_valid:
                return user
    
            return None
    
        def get_user(self, user_id):
            try:
                return User.objects.get(pk=user_id)
            except User.DoesNotExist:
                return None
    

    然后将新后端附加到可用后端列表中:

    AUTHENTICATION_BACKENDS = (
        'django.contrib.auth.backends.ModelBackend', # default
    
        ...
    
        'your_app.backends.LocalActiveBackend',
    )
    

    这将允许您在需要时通过密码和用户名进行简单的身份验证。