Django & React – 会话认证

huangapple go评论63阅读模式
英文:

Django & React - Session Authentication

问题

我在我的Django - React应用程序中使用会话认证。
但是,没有会话cookie存储在cookie存储中。
(存储了CSRF令牌cookie!)

我清除了本地存储/会话存储和cookies。
我尝试了不同的浏览器。

在前端部分,
我发出登录的POST请求:

axios.defaults.xsrfCookieName = "csrftoken";
axios.defaults.xsrfHeaderName = "X-CSRFToken";
axios.defaults.withCredentials = true;

const client = axios.create({
  baseURL: "http://127.0.0.1:8000",
});

function submitLogin(e) {
  e.preventDefault();
  setIsLoading(true);
  client
    .post("/login", {
      email: email,
      password: password,
    })
    .then(function (res) {
      setCurrentUser(true);
      window.location.reload(); // 登录后刷新页面
    })
    .catch(function (error) {
      setIsLoading(false);
    });
}

我得到了状态码200,用户已登录,一切似乎正常工作。
(在匿名窗口中打开应用程序时,登录不起作用!)

此外,我在开发工具中收到了SameSite属性错误:

指示是否通过指定其SameSite属性在跨站点请求中发送cookie

尽管我在settings.py中设置了所有内容:

SESSION_ENGINE = 'django.contrib.sessions.backends.db'
SESSION_COOKIE_SECURE = False  # 在开发中使用HTTP时将其设置为False
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = 'None'  # 如果使用跨站点请求
SESSION_COOKIE_SECURE = True  # 如果使用HTTPS

请注意,当设置为

SESSION_COOKIE_SAMESITE = 'lax''strict'

并且删除

SESSION_COOKIE_SECURE = True  # 如果使用HTTPS

登录不再起作用

我还尝试过不设置SESSION_ENGINE并使用默认值,但这没有任何区别(登录有效,但没有cookie)

在后端,我使用了自定义的User模型。
这是我的UserLogin视图:

class UserLogin(APIView):

    permission_classes = (permissions.AllowAny,)
    authentication_classes = (SessionAuthentication,)

    def post(self, request):
        data = request.data
        assert validate_email(data)
        assert validate_password(data)
        serializer = UserLoginSerializer(data=data)
        if serializer.is_valid(raise_exception=True):
            user = serializer.check_user(data)
            login(request, user)
            return Response(serializer.data, status=status.HTTP_200_OK)

我在INSTALLED_APPS中包括了corsheaders,在MIDDLEWARE的顶部添加了以下内容:

"corsheaders.middleware.CorsMiddleware",

我还添加了:

CORS_ALLOW_ALL_ORIGINS = True
CORS_ALLOW_CREDENTIALS = True

来自前端到后端的所有其他请求都正常工作!

我也相当确信rest framework已正确配置。我在INSTALLED_APPS中包括了rest_framework,并且:

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',
    ),
}

为什么没有存储会话cookie?

英文:

I am using session authentication in my Django - React application.
But no session cookie is stored in the cookie storage.
(A csrf token cookie is stored!)

I cleared the local storage / session storage and the cookies
I tried with different browsers

On the frontend Part,
I make a post request for the login:

axios.defaults.xsrfCookieName = "csrftoken";
axios.defaults.xsrfHeaderName = "X-CSRFToken";
axios.defaults.withCredentials = true;

const client = axios.create({
  baseURL: "http://127.0.0.1:8000",
});

  function submitLogin(e) {
    e.preventDefault();
    setIsLoading(true);
    client
      .post("/login", {
        email: email,
        password: password,
      })
      .then(function (res) {
        setCurrentUser(true);
        window.location.reload(); // Refresh the page after login
      })
      .catch(function (error) {
        setIsLoading(false);
      });
  }

I get a status code 200, user is logged in everything seems to work fine.
(When opening the application in a incognito window the log in is not working!)

Also I get a SameSite attribute error in dev tools:

> Indicate whether to send a cookie in a cross-site request by
> specifying its SameSite attribute

even though I set everything in settings.py:

SESSION_ENGINE = 'django.contrib.sessions.backends.db'
SESSION_COOKIE_SECURE = False  # Set it to False during development with HTTP
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = 'None'  # If using cross-site requests
SESSION_COOKIE_SECURE = True  # If using HTTPS

note that when setting

SESSION_COOKIE_SAMESITE = 'lax' or 'strict'

and removing

SESSION_COOKIE_SECURE = True  # If using HTTPS

the log in no longer works

I also tried without setting the SESSION_ENGINE and using the default but that makes no difference (the login works but no cookie)

On the backend site I use a custom User model
This is my UserLogin View:

class UserLogin(APIView):

	permission_classes = (permissions.AllowAny,)
	authentication_classes = (SessionAuthentication,)

    def post(self, request):
    		data = request.data
    		assert validate_email(data)
    		assert validate_password(data)
    		serializer = UserLoginSerializer(data=data)
    		if serializer.is_valid(raise_exception=True):
    			user = serializer.check_user(data)
    			login(request, user)
    			return Response(serializer.data, status=status.HTTP_200_OK)

I included corsheaders in the INSTALLED_APPS and in the MIDDLEWARE right at the top I put

"corsheaders.middleware.CorsMiddleware",

also I added:

CORS_ALLOW_ALL_ORIGINS = True
CORS_ALLOW_CREDENTIALS = True

All other requests from frontend to backend work fine!

I am also pretty sure rest framework is configured correctly I included rest_framework in the INSTALLED_APPS and:

REST_FRAMEWORK = { 
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',
    ),
}

Why is no session cookie stored?

答案1

得分: 1

尝试这样做:
在这里,我移除了重复的行 SESSION_COOKIE_SECURE

SESSION_ENGINE = 'django.contrib.sessions.backends.db'
SESSION_COOKIE_SECURE = True  # 如果使用 HTTPS
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = 'None'  # 如果使用跨站请求
英文:

try this way :
in this I remove the duplicate line SESSION_COOKIE_SECURE

SESSION_ENGINE = 'django.contrib.sessions.backends.db'
SESSION_COOKIE_SECURE = True  # If using HTTPS
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = 'None'  # If using cross-site requests
  

答案2

得分: 1

使用SessionAuthentication时,默认情况下Django需要两样东西:

  1. 当已登录用户处于活动状态时,需要cookies-key。
  2. 需要CSRF令牌。

如果这两者不匹配,就会引发错误,因此有文档可以指导正确认证的方法。

当你使用SessionAuthentication时,你正在使用Django的身份验证,通常需要检查CSRF。所以你必须在X-CSRFToken头部传递CSRF令牌。

这份文档提供了更多关于获取CSRF令牌和在请求中发送它的信息。CSRF令牌保存为名为csrftoken的cookie,你可以从HTTP响应中获取它。

如果无法获取CSRF cookie,通常意味着你不应该使用SessionAuthentication(而应该使用TokenAuthentication或OAuth 2.0)。

英文:

When you use SessionAuthentication, by default django requires 2 things

  1. cookies-key when a logged-in user is active
  2. csrf-token

If these do not match, then an error is raised, so, there is the documentation to make it authenticate in the correct way.<br>
When you are using SessionAuthentication, you are using Django's authentication which usually requires CSRF to be checked. So you must pass the CSRF token in the X-CSRFToken header.

This documentation provides more information on retrieving the CSRF token and sending it in requests. The CSRF token is saved as a cookie called csrftoken that you can retrieve from a HTTP response.

If you cannot retrieve the CSRF cookie, this is usually a sign that you should not be using SessionAuthentication (use TokenAuthentication or OAuth 2.0 instead).

huangapple
  • 本文由 发表于 2023年5月29日 04:55:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/76353562.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定