Django使用fetch实现登录

Django使用session管理(cookie)实现了一个用户登录和会话保持功能。如果需求不太复杂可以使用Django默认的登录功能。

1 安装django-cors-headers

首先需要安装django-cors-headers

pip install django-cors-headers

2 在settings中配置

需要按照django-cors-headers 官方说明进行配置。https://github.com/adamchainz/django-cors-headers

主要是以下几项:

from corsheaders.defaults import default_headers

INSTALLED_APPS = [
    ...,
    "corsheaders",
    ...,
]

MIDDLEWARE = [
    ...,
    "corsheaders.middleware.CorsMiddleware",
    "django.middleware.common.CommonMiddleware",
    ...,
]

# 这里写的是前端的地址,比如8080
CORS_ALLOWED_ORIGINS = [
    "https://example.com",
    "https://sub.example.com",
    "http://localhost:8080",
    "http://127.0.0.1:9000",
]

# 上面这个配置可以用下面的替换,直接允许所有的源
CORS_ALLOW_ALL_ORIGINS = True
# 这个是允许携带cookie
CORS_ALLOW_CREDENTIALS = True

# 配置header允许的字段
CORS_ALLOW_HEADERS = [
	*default_headers,
	'withCredentials',
]

SESSION_COOKIE_SAMESITE = "None"
SESSION_COOKIE_SECURE = True

3 在视图中使用Django提供的登录函数

https://docs.djangoproject.com/en/5.0/topics/auth/default/#django.contrib.auth.views.LoginView

from django.contrib.auth import authenticate, login


def my_view(request):
    username = request.POST["username"]
    password = request.POST["password"]
    user = authenticate(request, username=username, password=password)
    if user is not None:
        login(request, user)
        # Redirect to a success page.
        ...
    else:
        # Return an 'invalid login' error message.
        ...

这里注意,只有header中Content-Typex-www-form-urlencoded才可以这样解析,如果是application/json, 需要通过下面的方式:

data = json.loads(request.body)
username = data['username']
password = data['password']

4 使用fetch进行登录

在前端通过fetch或者axios发送请求,这里以fetch为例:

fetch(url, {
	headers: {
      'X-CSRFToken': csrftoken, //这个是可选的,如果禁用了csftoken则不需要。
      'Content-Type': 'x-www-form-urlencoded', //这里可以是application/json,后端需要方式二获取参数
      withCredentials: true //跨域时携带cookie
    },
    credentials: 'include', //要求携带cookie,否则无法维持会话
    body: JSON.stringify({
      username: xxx,
      password: xxx
    })
}).
then(res=>res.json()).
then(resJson=>{
	console.log(resJson) //这里处理登录结果
})

我们也可以包装为一个函数:

import Cookies from 'js-cookie'

const sendRequest = (url, method, data)=>{
  const csrftoken = Cookies.get('csrftoken')
  const options = {
    method: method,
    headers: {
      'X-CSRFToken': csrftoken,
      'Content-Type': 'application/json', //这里可以是application/json,后端需要方式二获取参数
      withCredentials: true //跨域时携带cookie
    },
    credentials: 'include', //要求携带cookie,否则无法维持会话
    body: JSON.stringify(data)
  }
  if(method != 'GET' && data) {
    options.body = JSON.stringify(data)
  }
  return fetch(`http://localhost:8000/${url}`, options)
}

5 验证登录是否成功

如果登录成功,则前端发送的请求都会带有一个user,后端可以这样获取:

def my_view(request):
	id = request.user.id

如果登录失败,则前端获取的id为None,用户为匿名用户。

遇到的问题

  1. “Origin checking failed … does not match any trusted origins”
    禁用csrf_token,具体做法:
  • 建立一个middleware:
class DisableCSRFMiddleware(object):

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        setattr(request, '_dont_enforce_csrf_checks', True)
        response = self.get_response(request)
        return response
  • 在settings中启用:
MIDDLEWARE = [
    'django.middleware.common.CommonMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    #'django.middleware.csrf.CsrfViewMiddleware',
    'myapp.middle.DisableCSRFMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',

]
  1. 使用非本机地址无法保持登录状态。
    一开始以为是GET无法cookie,后来改成POST还是同样问题。最后发现在http下传输会有安全维问题,需要在settings.py设置这两项:
SESSION_COOKIE_SAMESITE = None
SESSION_COOKIE_SECURE = False # 允许http传输cookie

在localhost下,即使http也是安全的,可以传输。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
步骤: 1. 安装pyjwt ``` pip install pyjwt ``` 2. 在Django中创建一个自定义的认证后端 ```python from django.contrib.auth.backends import BaseBackend from django.contrib.auth import get_user_model from jwt.exceptions import ExpiredSignatureError, InvalidTokenError from jwt import encode, decode User = get_user_model() class JWTAuthenticationBackend(BaseBackend): def authenticate(self, request, **kwargs): token = kwargs.get('token', None) if token: try: decoded = decode(token, 'secret', algorithms=['HS256']) user = User.objects.get(username=decoded['username']) return user except (ExpiredSignatureError, InvalidTokenError, User.DoesNotExist): return None return None def get_user(self, user_id): try: return User.objects.get(pk=user_id) except User.DoesNotExist: return None ``` 3. 在settings.py文件中配置认证后端 ```python AUTHENTICATION_BACKENDS = [ 'path.to.JWTAuthenticationBackend', 'django.contrib.auth.backends.ModelBackend', ] ``` 4. 在视图函数中添加JWT认证 ```python import datetime import jwt def login(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') user = authenticate(username=username, password=password) if user is not None: login(request, user) token = jwt.encode({'username': user.username, 'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=30)}, 'secret', algorithm='HS256') return JsonResponse({'token': token}) else: return JsonResponse({'error': 'Invalid credentials'}) ``` 5. 在需要认证的视图函数中添加装饰器 ```python from django.contrib.auth.decorators import login_required @login_required(login_url='/login/') def protected_view(request): return JsonResponse({'data': 'You are logged in'}) ``` 6. 在前端发送请求时带上JWT token ```javascript fetch('/protected_view/', { headers: { 'Authorization': 'Bearer ' + token } }) ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值