Вход пользователя с помощью ссылки входа - PullRequest
0 голосов
/ 01 февраля 2020

Я хочу отправить ссылку для входа пользователям.

Я знаю, что есть несколько приложений OneTimePassword с тысячами функций. Но я просто хочу какой-то простой и простой способ войти в систему через ссылку для входа в систему.

Мой вопрос, если это правильный путь к go по этому поводу. Как лучшие практики и DRY код.

Итак, я создал таблицу, которая хранит три строки. 1. «пользователь». Пользователь 2. «автогенерированный ключ». Автоматически сгенерированный ключ. 3. «create_at» A Отметка времени

Когда они войдут в систему, им будет отправлено письмо, содержащее ссылку для входа, действительную в течение nn минут. Таким образом, логин будет выглядеть примерно так:

https://example.net/login/?username=USERNAME&autogeneratedkey=KEY

Самое сложное для меня - найти хороший способ проверить это и войдите в систему пользователя. Я просто догадываюсь здесь. Но будет ли это хорошим подходом?

class login(generic.CreateView):
  def get(self, request, *args, **kwargs):
    try:
        autgeneratedkey = self.request.GET.get('autgeneratedkey', '')
        username = self.request.GET.get('username', '')

        obj_key = Login.objects.filter(autgeneratedkey=autgeneratedkey)[0]
        obj_user = Login.objects.filter(userusername=username)[0]

        try:
            if obj_user == obj_key: #Compare the objects if same
                if datetime.datetime.now() < (obj_key.created_at + datetime.timedelta(minutes=10)): #Check so the key is not older than 10min
                    u = CustomUser.objects.get(pk=obj_user.user_id)
                    login(request, u)
                    Login.objects.filter(autgeneratedkey=autgeneratedkey).delete()
                else:
                    return login_fail
            else:
                return login_fail

    except:
        return login_fail

    return redirect('index')

def login_fail(self, request, *args, **kwargs):
    return render(request, 'login/invalid_login.html')

Нелегко вызывать один и тот же пост, используя сначала autogeneratedkey, а затем имя пользователя. Также складывает, если-либо чувствует себя липким.

Ответы [ 2 ]

0 голосов
/ 01 февраля 2020

Вероятно, вы можете оптимизировать код следующим образом:

Сначала предположим, что у вас есть отношения между пользователем и моделью входа, как это:

class Login(models.Model):
    user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)

Затем вы можете использовать вид, подобный этому:

class LoginView(generic.View):
  def get(self, request, *args, **kwargs):
    try:
        autgeneratedkey = self.request.GET.get('autgeneratedkey', '')
        username = self.request.GET.get('username', '')           
        user = CustomUser.objects.get(login__autgeneratedkey=autgeneratedkey, username=username, login__created_at__gte=datetime.now()-datetime.timedelta(minutes=10))
        login(request, user)
        user.login_set.all().delete()  # delete all login objects

    except CustomUser.DoesNotExist:
        return login_fail

    return redirect('index')

Другое дело, что не рекомендуется использовать метод GET для обновления базы данных. Методы GET должны быть идемпотентными . Лучше использовать почтовый метод здесь. Просто разрешите пользователю щелкнуть ссылку (которая будет обрабатываться другим представлением шаблона), а затем из этого шаблона использовать ajax, чтобы сделать запрос POST для этого представления.

0 голосов
/ 01 февраля 2020

Я бы не отправлял имя пользователя в запросе get. Просто отправьте автоматически сгенерированный ключ.

http://example.com/login?key=random-long-string

Затем эта схема БД (это новая таблица, потому что я не знаю, Login уже используется.

LoginKey ( id [PK], user [FK(CustomUser)], key [Unique], expiry )

Когда пользователь отправляет электронное письмо, вы создаете новый LoginKey.

Затем делаете что-то вроде этого:

def get(self, request, *args, **kwargs):
  key = request.GET.get('key', '')
  if not key:
    return login_fail

  login_key = LoginKey.objects.get(key=key)
  if login_key is None or datetime.datetime.now() > login_key.expiry:
    return login_fail

  u = login_key.user
  login(request, u)
  login_key.delete()
  return redirect('index')
...