代码之家  ›  专栏  ›  技术社区  ›  Jordan Regan

仅在响应中保护HTTP cookie,但不保护请求

  •  0
  • Jordan Regan  · 技术社区  · 2 年前

    我的仅HTTP cookie被前端接收,但在随后的请求中没有传递到后端,因此破坏了我的身份验证过程。

    我想在我的React应用程序中为页面添加身份验证。其中一部分涉及到向我的Django API发出经过身份验证的请求。端点是使用以下身份验证类设置的:

    from rest_framework.authentication import TokenAuthentication
    from rest_framework.exceptions import AuthenticationFailed
    
    class CookieTokenAuthentication(TokenAuthentication):
    
        def authenticate(self, request):
            token = request.COOKIES.get('authToken')
            print(f'Cookies: {request.COOKIES}') # printing cookies for debugging
            print(f'Token: {token}')
    
            if not token:
                raise AuthenticationFailed('No token provided')
    
            token_model = self.get_model()
    
            try:
                token_obj = token_model.objects.get(key=token)
            except token_model.DoesNotExist:
                raise AuthenticationFailed('Invalid token')
    
            if token_obj.expiry < timezone.now():
                raise AuthenticationFailed('Token expired')
    
            return (token_obj.user, token_obj)
    

    由于这需要authToken,所以我已经基于默认用户模型生成了authToken。下面是这样做的课程:

        authentication_classes = []
    
        def post(self, request, *args, **kwargs):
            serializer = self.serializer_class(data=request.data,
                                               context={'request': request})
            serializer.is_valid(raise_exception=True)
            user = serializer.validated_data['user']
            expiry = timezone.now() + timedelta(days=7)
            token, created = Token.objects.get_or_create(user=user)
            if not created:
                token.expiry = expiry
                token.save()
            response = Response({
                'user_id': user.pk,
                'expiry': expiry.isoformat()
            })
            response.set_cookie(
                key='authToken', 
                value=token.key, 
                httponly=True, 
                secure=True, 
                samesite='None', 
                expires=expiry,
                domain='localhost',
                path='/'
                )
            return response
    

    我可以验证authToken是否发送给用户,因为我可以在用户登录的响应中看到“set_cookie”标头。 我不得不把它做成一个只使用HTTP的cookie,因为我不想受到XSS攻击。显然是什么时候 samesite='False' 你还需要设置 secure=True ,所以我不得不走HTTPS路线。。。

    我已经使用OpenSSL生成了一个自签名SSL证书,用于在localhost上进行开发。然后,我将React前端和Django后端配置为使用HTTPS启动。我为Django安装了Django-extensions/Werkzeug并运行了一个指向证书/私钥的命令,为React在“vite.config.js”中指定了HTTPS和证书/密钥。前端和后端服务器都在HTTPS上运行。

    然后,我在Chrome中遇到了一些问题,网页不安全,所以我启用了Chrome标志“允许不安全的本地主机”,并将本地主机证书添加到“受信任的根证书颁发机构”。在重新启动缓存并在Chrome中重新加载我的网络应用程序后,我登录了我的网站。当用户登录时,它在HTTPS响应标头中发送了cookie,但随后的请求不包含cookie(我用我在本文中显示的身份验证类检查了这一点,该类打印了请求的cookie)。

    我的相关Django设置如下:

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'rest_framework',
        'django_filters',
        'EstrayaApp.apps.EstrayaappConfig',
        'corsheaders',
        'rest_framework.authtoken',
        'django_extensions',
    ]
    
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'corsheaders.middleware.CorsMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'EstrayaApp.middleware.TokenExpiryMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]
    
    CSRF_COOKIE_SECURE = True
    CSRF_COOKIE_HTTPONLY = True
    SESSION_COOKIE_SECURE = True
    SESSION_COOKIE_HTTPONLY = True
    SESSION_COOKIE_SAMESITE = 'None'
    CSRF_COOKIE_SAMESITE = 'None'
    
    CORS_ALLOW_CREDENTIALS = True
    
    CORS_ALLOWED_ORIGINS = [
        'https://localhost:5173',
        'https://localhost:8000',
        ]
    
    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': [
            'EstrayaApp.authentication.CookieTokenAuthentication',
            'rest_framework.authentication.TokenAuthentication',
        ]
    }
    

    最后,这里是React函数,它正在发出经过身份验证的请求:

      const fetchTargetSkill = async (skill) => {
        const response = await fetch(`https://127.0.0.1:8000/usertask-byskill/${skill.id}/`, {
          method: 'GET',
          credentials: 'include',
        });
    

    我觉得我什么都试过了。没有人的帖子是直接相关的,我现在迷路了。任何帮助都将不胜感激,谢谢。

    0 回复  |  直到 2 年前
    推荐文章