simplejwt token为所有django-tenants的租户工作

g52tjvyc  于 2023-10-21  发布在  Go
关注(0)|答案(1)|浏览(107)

我只想谈谈我的问题。我已经研究了很多文件,但我找不到任何解决方案。
我只是尝试使用django-tenants。一切正常。但如果任何用户在登录后获得令牌,该令牌对所有租户都有效。
这是一个很大的安全漏洞。
我一直在想一个主意SIGNING_KEY。如果我可以改变每个租户的SIGNING_KEY,它可能是固定的。但事实并非如此。

class TenantJWTAuthenticationMiddleware(MiddlewareMixin):
  def process_request(self, request):
    tenant = Client.objects.get(schema_name=connection.schema_name)
    jwt_secret_key = tenant.jwt_secret_key
    settings.SIMPLE_JWT['SIGNING_KEY'] = jwt_secret_key

这是我的中间件更改每个租户的SIGNING_KEY。

class Client(TenantMixin):
  name = models.CharField(max_length=100)
  paid_until =  models.DateField()
  on_trial = models.BooleanField()
  created_on = models.DateField(auto_now_add=True)
  jwt_secret_key = models.CharField(max_length=100, null=True, blank=True)

  # default true, schema will be automatically created and synced when it is saved
  auto_create_schema = True

class Domain(DomainMixin):
  pass

这是我的模型。
因此,我将jwt_secret_key添加到我的模型中,并在Middleware中获取此字段,并尝试为jwt设置SIGNING_KEY。但是,用户登录后的jwt仍然可以用于所有租户。
有人知道我的问题吗?对我的解决方案有什么建议或修正吗?
谢谢.

mbjcgjjk

mbjcgjjk1#

通过创建一个自定义序列化器,继承djangorestframework-simplejwt的TokenObtainPairSerializer,并在get_token函数中传递额外的数据,可以基于db连接将模式数据传递给jwt令牌。然后可以在从TokenObtainPairView继承的自定义视图中使用此序列化程序。

from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from django.db import connection

class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        token = super().get_token(user)
        token["tenant_schema"] = connection.schema_name
        return token

class CustomTokenObtainPairView(TokenObtainPairView):

    serializer_class = CustomTokenObtainPairSerializer
    token_obtain_pair = TokenObtainPairView.as_view()

然后使用此视图获取令牌

path("token/", CustomTokenObtainPairView.as_view(), name="token_obtain_pair")

为了验证这个令牌,你必须为django rest framework创建一个自定义的身份验证类,并将访问令牌tenant_schema与当前连接模式(来自另一个租户)进行比较,如果模式不同,不要返回身份验证数据。

from rest_framework_simplejwt.authentication import JWTAuthentication
from django.db import connection

class CustomJWTAuthentication(JWTAuthentication):

    def authenticate(self, request):
        if auth := super().authenticate(request):
            user, token = auth
            if token.payload["tenant_schema"] == connection.schema_name:
                return user, token
        return None

然后在项目设置中更改DEFAULT_AUTHENTICATION_CLASSES

REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": (
        "path.to.CustomJWTAuthentication",
    ),
}

我认为您可以使用jwt_secret_key字段实现类似的功能,因为您可以像在中间件中使用connection.schema_name一样获取租户对象,并将任何租户数据添加到令牌中。然而,我认为一个模式名就足够了,没有必要为jwt令牌向租户模型添加额外的字段。

相关问题