maquinaweb-shared-auth 0.1.6__py3-none-any.whl → 0.1.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of maquinaweb-shared-auth might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maquinaweb-shared-auth
3
- Version: 0.1.6
3
+ Version: 0.1.8
4
4
  Summary: Models read-only para autenticação compartilhada entre projetos Django.
5
5
  Author-email: Seu Nome <seuemail@dominio.com>
6
6
  License: MIT
@@ -0,0 +1,18 @@
1
+ shared_auth/__init__.py,sha256=Ta8lIbyn22J6wU-TgWeSvdDHS4NBRf4Sv1Ag8VtY-bE,152
2
+ shared_auth/app.py,sha256=EHoLKlpW41o6ZxcH184aMhnWQxkVp9fH2_-89RjMz-4,215
3
+ shared_auth/authentication.py,sha256=btrTjBszPrKKfKA4F0pOOzaxnfASgXb1y2cxQwOWbnk,1515
4
+ shared_auth/conf.py,sha256=-jdnCokMvWvVKllfsxNYCsPk1Vo3MDRq4Y1MsO16oeA,411
5
+ shared_auth/decorators.py,sha256=k1GurkcJUL_WKK1wNEfFNfjo5Td_S7v5YI_3E-zi9kc,3336
6
+ shared_auth/exceptions.py,sha256=eiII-REupK6GeFinisteYO3FsGUDAN5zAajXPhTREm8,404
7
+ shared_auth/fields.py,sha256=RAcmFh1D_nkbai_7t_OrPZhfhAipesy5kKnEj4LUvvM,1254
8
+ shared_auth/managers.py,sha256=ykfa11rMR3axuc_Kl_ab_SJ_R6pufwJS2h3SVr318-w,7089
9
+ shared_auth/middleware.py,sha256=4IUr5qWEpJfhwCkUTxv8jkcltasn2ZFuCWL93qrK6jI,6270
10
+ shared_auth/mixins.py,sha256=3ARghQ4TvtENKoA5UTOHTrRHa6ufMRVJJHGFkV8-BL8,7550
11
+ shared_auth/models.py,sha256=tMT84SA99V7lt-nfvP73fklN6pAidWxgHO04NgEZh3M,5342
12
+ shared_auth/permissions.py,sha256=t1YVLBKnpAo4pmSNvqC9mW08CdOE99q2fpf-Heuo_Bs,2712
13
+ shared_auth/router.py,sha256=SbM5YEoxxg2zMns1kfFmsK9YrgqqVfc4-riniYY7rbQ,651
14
+ shared_auth/serializers.py,sha256=TDpuZVsOL-6igINSOOOyELWbTUeet4XWRoBkvcMGjW4,4290
15
+ maquinaweb_shared_auth-0.1.8.dist-info/METADATA,sha256=WMNJObfGD6DhTXlqScKnEBlL68x8qlWOPhEeJrNhuig,27150
16
+ maquinaweb_shared_auth-0.1.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
17
+ maquinaweb_shared_auth-0.1.8.dist-info/top_level.txt,sha256=msyYRy02ZV7zz7GR1raUI5LXGFIFn2TIkgkeKZqKufE,12
18
+ maquinaweb_shared_auth-0.1.8.dist-info/RECORD,,
shared_auth/__init__.py CHANGED
@@ -1,21 +1,6 @@
1
1
  """
2
2
  Biblioteca compartilhada para acesso aos models de autenticação
3
3
  """
4
- from .models import (
5
- SharedOrganization,
6
- SharedUser,
7
- SharedMember,
8
- )
9
- from .exceptions import (
10
- OrganizationNotFoundError,
11
- UserNotFoundError,
12
- )
13
4
 
14
5
  __version__ = '1.0.0'
15
- __all__ = [
16
- 'SharedOrganization',
17
- 'SharedUser',
18
- 'SharedMember',
19
- 'OrganizationNotFoundError',
20
- 'UserNotFoundError',
21
- ]
6
+ default_app_config = "shared_auth.app.SharedAuthConfig"
shared_auth/app.py CHANGED
@@ -3,4 +3,7 @@ from django.apps import AppConfig
3
3
 
4
4
  class SharedAuthConfig(AppConfig):
5
5
  default_auto_field = "django.db.models.BigAutoField"
6
- name = "shared_auth"
6
+ name = "shared_auth"
7
+
8
+ def ready(self):
9
+ from . import models, exceptions
shared_auth/decorators.py CHANGED
@@ -3,8 +3,10 @@ Decorators para views funcionais
3
3
  """
4
4
 
5
5
  from functools import wraps
6
+
6
7
  from django.http import JsonResponse
7
- from .models import SharedToken, SharedUser, SharedOrganization
8
+
9
+ from .models import SharedOrganization, SharedToken, SharedUser
8
10
 
9
11
 
10
12
  def require_auth(view_func):
@@ -52,16 +54,13 @@ def require_organization(view_func):
52
54
  @wraps(view_func)
53
55
  @require_auth
54
56
  def wrapped_view(request, *args, **kwargs):
55
- if (
56
- not hasattr(request.user, "logged_organization_id")
57
- or not request.user.logged_organization_id
58
- ):
57
+ if not hasattr(request, "organization_id") or not request.organization_id:
59
58
  return JsonResponse({"error": "Organização não definida"}, status=403)
60
59
 
61
60
  # Buscar organização
62
61
  try:
63
62
  org = SharedOrganization.objects.using("auth_db").get(
64
- pk=request.user.logged_organization_id
63
+ pk=request.organization_id
65
64
  )
66
65
 
67
66
  if not org.is_active():
@@ -94,8 +93,6 @@ def require_same_organization(view_func):
94
93
 
95
94
  # Aqui você precisa buscar o objeto e verificar
96
95
  # Exemplo genérico - adapte conforme seu model
97
- from django.apps import apps
98
-
99
96
  # Tentar identificar o model pelo path
100
97
  # Esta é uma implementação básica
101
98
  # Em produção, você pode passar o model como parâmetro
shared_auth/managers.py CHANGED
@@ -3,6 +3,7 @@ Managers customizados para os models compartilhados
3
3
  """
4
4
 
5
5
  from django.db import models
6
+ from django.contrib.auth.models import UserManager
6
7
  from .exceptions import OrganizationNotFoundError, UserNotFoundError
7
8
 
8
9
 
@@ -43,7 +44,7 @@ class SharedOrganizationManager(models.Manager):
43
44
  return self.filter(cnpj__contains=clean_cnpj).first()
44
45
 
45
46
 
46
- class SharedUserManager(models.Manager):
47
+ class SharedUserManager(UserManager):
47
48
  """Manager para SharedUser"""
48
49
 
49
50
  def get_or_fail(self, user_id):
shared_auth/middleware.py CHANGED
@@ -2,12 +2,11 @@
2
2
  Middlewares para autenticação compartilhada
3
3
  """
4
4
 
5
- from django.utils.deprecation import MiddlewareMixin
6
5
  from django.http import JsonResponse
6
+ from django.utils.deprecation import MiddlewareMixin
7
7
 
8
- from . import SharedMember
9
8
  from .authentication import SharedTokenAuthentication
10
- from .models import SharedToken, SharedUser, SharedOrganization
9
+ from .models import SharedMember, SharedOrganization, SharedToken, SharedUser
11
10
 
12
11
 
13
12
  class SharedAuthMiddleware(MiddlewareMixin):
@@ -46,7 +45,7 @@ class SharedAuthMiddleware(MiddlewareMixin):
46
45
  token = self._get_token_from_request(request)
47
46
 
48
47
  if not token:
49
- request.user = None
48
+ # request.user = None
50
49
  request.auth = None
51
50
  return None
52
51
 
@@ -56,16 +55,16 @@ class SharedAuthMiddleware(MiddlewareMixin):
56
55
  user = SharedUser.objects.using("auth_db").get(pk=token_obj.user_id)
57
56
 
58
57
  if not user.is_active or user.deleted_at is not None:
59
- request.user = None
58
+ # request.user = None
60
59
  request.auth = None
61
60
  return None
62
61
 
63
62
  # Adicionar ao request
64
- request.user = user
63
+ # request.user = user
65
64
  request.auth = token_obj
66
65
 
67
66
  except (SharedToken.DoesNotExist, SharedUser.DoesNotExist):
68
- request.user = None
67
+ # request.user = None
69
68
  request.auth = None
70
69
 
71
70
  return None
@@ -149,6 +148,9 @@ class OrganizationMiddleware(MiddlewareMixin):
149
148
  organization_id = self._determine_organization_id(request)
150
149
  user = self._authenticate_user(request)
151
150
 
151
+ if not organization_id and not user:
152
+ return
153
+
152
154
  if organization_id and user:
153
155
  organization_id = self._validate_organization_membership(
154
156
  user, organization_id
@@ -157,9 +159,12 @@ class OrganizationMiddleware(MiddlewareMixin):
157
159
  return
158
160
 
159
161
  request.organization_id = organization_id
160
- request.organization = SharedOrganization.objects.get_or_fail(organization_id)
161
- request.user.logged_organization_id = organization_id
162
- request.user.save()
162
+ request.organization = (
163
+ SharedOrganization.objects.using("auth_db")
164
+ .filter(pk=organization_id)
165
+ .first()
166
+ )
167
+
163
168
  @staticmethod
164
169
  def _authenticate_user(request):
165
170
  data = SharedTokenAuthentication().authenticate(request)
@@ -172,6 +177,7 @@ class OrganizationMiddleware(MiddlewareMixin):
172
177
  return org_id
173
178
 
174
179
  return self._get_organization_from_user(request)
180
+
175
181
  @staticmethod
176
182
  def _get_organization_from_header(request):
177
183
  if header_value := request.headers.get("X-Organization"):
@@ -180,22 +186,26 @@ class OrganizationMiddleware(MiddlewareMixin):
180
186
  except (ValueError, TypeError):
181
187
  pass
182
188
  return None
189
+
183
190
  @staticmethod
184
191
  def _get_organization_from_user(request):
192
+ """
193
+ Retorna a primeira organização do usuário autenticado
194
+ """
185
195
  if not request.user.is_authenticated:
186
196
  return None
187
197
 
188
- if (
189
- hasattr(request.user, "logged_organization")
190
- and request.user.logged_organization
191
- ):
192
- return request.user.logged_organization.id
198
+ # Buscar a primeira organização que o usuário pertence
199
+ member = (
200
+ SharedMember.objects.using("auth_db")
201
+ .filter(user_id=request.user.pk)
202
+ .first()
203
+ )
204
+
205
+ return member.organization_id if member else None
193
206
 
194
- return None
195
207
  @staticmethod
196
- def _validate_organization_membership(
197
- user, organization_id
198
- ):
208
+ def _validate_organization_membership(user, organization_id):
199
209
  try:
200
210
  member = get_member(user, organization_id)
201
211
  if not member and not user.is_superuser:
@@ -204,5 +214,8 @@ class OrganizationMiddleware(MiddlewareMixin):
204
214
  except Exception:
205
215
  return None
206
216
 
217
+
207
218
  def get_member(user, organization_id):
208
- return SharedMember.objects.filter(user_id=user.pk, organization_id=organization_id).first()
219
+ return SharedMember.objects.filter(
220
+ user_id=user.pk, organization_id=organization_id
221
+ ).first()
shared_auth/models.py CHANGED
@@ -3,12 +3,14 @@ Models READ-ONLY para acesso aos dados de autenticação
3
3
  ATENÇÃO: Estes models NÃO devem ser usados para criar migrations
4
4
  """
5
5
 
6
+ from django.contrib.auth.models import AbstractUser
6
7
  from django.db import models
7
- from .conf import ORGANIZATION_TABLE, USER_TABLE, MEMBER_TABLE
8
+
9
+ from .conf import MEMBER_TABLE, ORGANIZATION_TABLE, USER_TABLE
8
10
  from .managers import (
11
+ SharedMemberManager,
9
12
  SharedOrganizationManager,
10
13
  SharedUserManager,
11
- SharedMemberManager,
12
14
  )
13
15
 
14
16
 
@@ -132,23 +134,15 @@ class SharedOrganization(models.Model):
132
134
  return self.deleted_at is None
133
135
 
134
136
 
135
- class SharedUser(models.Model):
137
+ class SharedUser(AbstractUser):
136
138
  """
137
139
  Model READ-ONLY da tabela auth_user
138
140
  """
139
141
 
140
- username = models.CharField(max_length=150)
141
- first_name = models.CharField(max_length=150, blank=True)
142
- last_name = models.CharField(max_length=150, blank=True)
143
- email = models.EmailField()
144
- is_staff = models.BooleanField(default=False)
145
- is_active = models.BooleanField(default=True)
146
- is_superuser = models.BooleanField(default=False)
147
142
  date_joined = models.DateTimeField()
148
143
  last_login = models.DateTimeField(null=True, blank=True)
149
144
 
150
145
  # Campos customizados
151
- logged_organization_id = models.IntegerField(null=True, blank=True)
152
146
  createdat = models.DateTimeField()
153
147
  updatedat = models.DateTimeField()
154
148
  deleted_at = models.DateTimeField(null=True, blank=True)
@@ -160,51 +154,6 @@ class SharedUser(models.Model):
160
154
  db_table = USER_TABLE
161
155
  app_label = "shared_auth"
162
156
 
163
- def __str__(self):
164
- return self.get_full_name() or self.username
165
-
166
- def get_full_name(self):
167
- """Retorna nome completo"""
168
- return f"{self.first_name} {self.last_name}".strip()
169
-
170
- @property
171
- def logged_organization(self):
172
- """
173
- Acessa organização logada (lazy loading)
174
-
175
- Usage:
176
- user = SharedUser.objects.get(pk=1)
177
- org = user.logged_organization
178
- print(org.name)
179
- """
180
- if self.logged_organization_id:
181
- return SharedOrganization.objects.get_or_fail(self.logged_organization_id)
182
- return None
183
-
184
- @property
185
- def organizations(self):
186
- """
187
- Retorna todas as organizações do usuário
188
-
189
- Usage:
190
- orgs = user.organizations
191
- """
192
- member_orgs = SharedMember.objects.for_user(self.pk)
193
- org_ids = member_orgs.values_list("organization_id", flat=True)
194
- return SharedOrganization.objects.filter(pk__in=org_ids)
195
-
196
- @property
197
- def memberships(self):
198
- """
199
- Retorna memberships do usuário
200
-
201
- Usage:
202
- memberships = user.memberships
203
- for m in memberships:
204
- print(m.organization.name)
205
- """
206
- return SharedMember.objects.for_user(self.pk)
207
-
208
157
 
209
158
  class SharedMember(models.Model):
210
159
  """
@@ -4,6 +4,8 @@ Permissões customizadas para DRF
4
4
 
5
5
  from rest_framework import permissions
6
6
 
7
+ from shared_auth.middleware import get_member
8
+
7
9
 
8
10
  class IsAuthenticated(permissions.BasePermission):
9
11
  """
@@ -26,10 +28,10 @@ class HasActiveOrganization(permissions.BasePermission):
26
28
  message = "Organização ativa necessária."
27
29
 
28
30
  def has_permission(self, request, view):
29
- if not request.user or not hasattr(request.user, "logged_organization_id"):
31
+ if not request.user or not hasattr(request, "organization_id"):
30
32
  return False
31
33
 
32
- if not request.user.logged_organization_id:
34
+ if not request.organization_id:
33
35
  return False
34
36
 
35
37
  # Verificar se organização está ativa
@@ -37,7 +39,7 @@ class HasActiveOrganization(permissions.BasePermission):
37
39
 
38
40
  try:
39
41
  org = SharedOrganization.objects.using("auth_db").get(
40
- pk=request.user.logged_organization_id
42
+ pk=request.organization_id
41
43
  )
42
44
  return org.is_active()
43
45
  except SharedOrganization.DoesNotExist:
@@ -54,13 +56,17 @@ class IsSameOrganization(permissions.BasePermission):
54
56
  message = "Você não tem permissão para acessar este recurso."
55
57
 
56
58
  def has_object_permission(self, request, view, obj):
57
- if not hasattr(request.user, "logged_organization_id"):
59
+ if not hasattr(request, "organization_id"):
58
60
  return False
59
61
 
60
62
  if not hasattr(obj, "organization_id"):
61
63
  return True # Se objeto não tem org, permite
62
64
 
63
- return obj.organization_id == request.user.logged_organization_id
65
+ # Verifica se o usuário é membro da organização do objeto
66
+ if not get_member(request.user, obj.organization_id):
67
+ return False
68
+
69
+ return obj.organization_id == request.organization_id
64
70
 
65
71
 
66
72
  class IsOwnerOrSameOrganization(permissions.BasePermission):
@@ -78,9 +84,9 @@ class IsOwnerOrSameOrganization(permissions.BasePermission):
78
84
  return True
79
85
 
80
86
  # Verificar se é da mesma organização
81
- if hasattr(obj, "organization_id") and hasattr(
82
- request.user, "logged_organization_id"
83
- ):
84
- return obj.organization_id == request.user.logged_organization_id
87
+ if hasattr(obj, "organization_id") and hasattr(request, "organization_id"):
88
+ # Verifica se o usuário é membro da organização do objeto
89
+ if get_member(request.user, obj.organization_id):
90
+ return obj.organization_id == request.organization_id
85
91
 
86
92
  return False
@@ -1,18 +0,0 @@
1
- shared_auth/__init__.py,sha256=WbDmRRdOp0nn5I_ksYjhAa2HRtXe0wxtGY6qnaiPlB8,397
2
- shared_auth/app.py,sha256=aOgzojmmabOvWfNqw7YFaM6L_dB8lsnF_No5HiRTFPk,152
3
- shared_auth/authentication.py,sha256=btrTjBszPrKKfKA4F0pOOzaxnfASgXb1y2cxQwOWbnk,1515
4
- shared_auth/conf.py,sha256=-jdnCokMvWvVKllfsxNYCsPk1Vo3MDRq4Y1MsO16oeA,411
5
- shared_auth/decorators.py,sha256=LTDHiVX36O65jbcCUqtoNPNkQ1suDH4fICXVyduZ1BM,3444
6
- shared_auth/exceptions.py,sha256=eiII-REupK6GeFinisteYO3FsGUDAN5zAajXPhTREm8,404
7
- shared_auth/fields.py,sha256=RAcmFh1D_nkbai_7t_OrPZhfhAipesy5kKnEj4LUvvM,1254
8
- shared_auth/managers.py,sha256=yPv40NxoOWyrJygLt6xYAHGAlKcvOYGRoUb6zKqLm4Y,7041
9
- shared_auth/middleware.py,sha256=y2blhI44nJL39UqyOxBgJjiafwuZEb7G0Zlvfge6rlo,6068
10
- shared_auth/mixins.py,sha256=3ARghQ4TvtENKoA5UTOHTrRHa6ufMRVJJHGFkV8-BL8,7550
11
- shared_auth/models.py,sha256=iszFHOhpD78tqcXaxxZ9_57wLdRq9i_ZsHWrfy5W9Nc,6997
12
- shared_auth/permissions.py,sha256=kkEMtClmV9VB3EOhKDyinSr4r5v9g-3DCCKNtqpaTz8,2473
13
- shared_auth/router.py,sha256=SbM5YEoxxg2zMns1kfFmsK9YrgqqVfc4-riniYY7rbQ,651
14
- shared_auth/serializers.py,sha256=TDpuZVsOL-6igINSOOOyELWbTUeet4XWRoBkvcMGjW4,4290
15
- maquinaweb_shared_auth-0.1.6.dist-info/METADATA,sha256=5iR99adsbbr8A5lCgPUrMDsfACRDdJyUnq1E48Jlc7w,27150
16
- maquinaweb_shared_auth-0.1.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
17
- maquinaweb_shared_auth-0.1.6.dist-info/top_level.txt,sha256=msyYRy02ZV7zz7GR1raUI5LXGFIFn2TIkgkeKZqKufE,12
18
- maquinaweb_shared_auth-0.1.6.dist-info/RECORD,,