Как выйти из системы, когда он меняет пароль из всех браузеров (Django-rest-auth, JWT)? - PullRequest
0 голосов
/ 12 апреля 2019

Прежде всего, я новичок в django-rest-framework, поэтому, пожалуйста, извините, если я ошибаюсь.

Я работаю с django-rest-auth и django-restframework-jwt для аутентификации пользователей.Я сохраняю токен jwt в localStorage каждый раз, когда пользователь входит в систему.

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

Я хотел сделать его токен JWT недействительным при смене пароля, чтобы он автоматически выходил из системы.Но я не смог найти способ истечения срока действия его токена в официальной документации Django REST framework JWT

Я попытался отследить момент смены пароля, вручную сгенерировав новый токен JWT для пользователя,но это не работает (возможно, потому что существующий токен все еще действителен)

@receiver(signals.pre_save, sender=User)
def revoke_tokens(sender, instance, **kwargs):
    existing_user = User.objects.get(pk=instance.pk)

    if getattr(settings, 'REST_USE_JWT', False):
        if instance.password != existing_user.password:
            # If user has changed his password, generate manually a new token for him
            jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
            jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
            payload = jwt_payload_handler(instance)
            payload['orig_iat'] = timegm(datetime.utcnow().utctimetuple())
            instance.token = jwt_encode_handler(payload)

После прочтения некоторых документов и сообщений, кажется, что это не совсем просто, только с jwt, так как он не имеет состояния, но можеткто-нибудь указывает мне направление, куда идти?

Должен ли я удалить JWT аутентификацию?

Есть ли способ, который может мне помочь в этом?

Большое спасибо.


РЕДАКТИРОВАТЬ:

Я нашел комментарий в аналогичную запись на SO @Travis о том, что

Распространенный подход для аннулирования токенов, когда пользователь меняет свой пароль, состоит в том, чтобы подписать токен хешем своего пароля.Таким образом, если пароль изменяется, любые предыдущие токены автоматически не проходят проверку.Вы можете расширить это до выхода из системы, включив время последнего выхода из системы в записи пользователя и используя комбинацию времени последнего выхода из системы и хэша пароля для подписи токена.Это требует поиска в БД каждый раз, когда вам нужно проверить подпись токена, но, по-видимому, вы все равно ищете пользователя

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

Ответы [ 2 ]

0 голосов
/ 19 апреля 2019

После нескольких дней работы я перезаписал JWT_PAYLOAD_HANDLER и добавил последние цифры хеша пароля пользователя в токене JWT (поскольку добавление всего хэша пароля в полезную нагрузку не является хорошая практика) а затем создать custom middleware, который перехватывает все запросы.

в каждом запросе я проверяю с jwt token, совпадает ли хеш пароля с существующим хешем пользователя (если нет, это означает, что пользователь изменил свой пароль)

если они разные, я выдаю ошибку и выхожу из системы со старым хэшем пароля.

в конфигурационном файле:

    'JWT_PAYLOAD_HANDLER': 'your.path.jwt.jwt_payload_handler',

и в корне указано в файле конфигурации:

 def jwt_payload_handler(user):
      username_field = get_username_field()
      username = get_username(user)

      payload = {
    'user_id': user.pk,
    'username': username,
    'pwd': user.password[-10:],
    'exp': datetime.utcnow() + api_settings.JWT_EXPIRATION_DELTA
    }
if hasattr(user, 'email'):
    payload['email'] = user.email
if isinstance(user.pk, uuid.UUID):
    payload['user_id'] = str(user.pk)

      payload[username_field] = username
      return payload

а затем это пользовательское промежуточное ПО:

from django.http.response import HttpResponseForbidden
from django.utils.deprecation import MiddlewareMixin
from rest_framework_jwt.utils import jwt_decode_handler
from config.settings.base import JWT_AUTH
from trp.users.models import User
class JWTAuthenticationMiddleware(MiddlewareMixin):
   def process_request(self, request):
      jwt_user_pwd = self.get_jwt_user_pwd(request)
      # check if last digits of password read from jwt token matches the hash of the current user in DB
      if jwt_user_pwd is not None:
        if jwt_user_pwd['pwd'] != jwt_user_pwd['user'].password[-10:]:
            return HttpResponseForbidden()

@staticmethod
def get_jwt_user_pwd(request):
    token = request.META.get('HTTP_AUTHORIZATION', None)
    # Remove the prefix from token name so that decoding the token gives us correct credentials
    token = str(token).replace(JWT_AUTH['JWT_AUTH_HEADER_PREFIX'] + ' ', '')
    if token:
        try:
            payload = jwt_decode_handler(token)
            authenticated_user = User.objects.get(id=payload['user_id'])
        except Exception as e:
            authenticated_user = None
            payload = {}
        if authenticated_user and payload:
            return {'user': authenticated_user, 'pwd': payload.get('pwd')}
    return None

Чтобы выйти из системы, я прочитал код состояния запроса «в данном случае 403» из внешнего интерфейса: (я использую Angular в моем случае), а затем вышел из системы. Я надеюсь, что это поможет кому-то в будущем.

0 голосов
/ 13 апреля 2019

Ну,

Это все о времени истечения токена - если вы будете так коротко (например, 10-15 минут) - вы не сможете утратить силу, если его пароль или некоторые разрешения будут изменены. Токен будет недействительным всегда через некоторое время, и будет выпущен новый.

Если вы используете JWT как долгоживущий токен (что не является хорошей практикой) - у вас будут проблемы.

Поскольку такие действия, как смена пароля и аннулирование других токенов (другой сеанс) (или принудительное повторное создание), должны храниться где-то еще (например, в некотором хранилище NoSQL) - и проверяться для каждого сеанса, что требуется какое-то специальное действие, - и тогда вы теряют преимущество без гражданства JWT.

...