maquinaweb-shared-auth 0.2.60__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.
- maquinaweb_shared_auth-0.2.60.dist-info/METADATA +1003 -0
- maquinaweb_shared_auth-0.2.60.dist-info/RECORD +28 -0
- maquinaweb_shared_auth-0.2.60.dist-info/WHEEL +5 -0
- maquinaweb_shared_auth-0.2.60.dist-info/top_level.txt +1 -0
- shared_auth/__init__.py +7 -0
- shared_auth/abstract_models.py +897 -0
- shared_auth/app.py +9 -0
- shared_auth/authentication.py +55 -0
- shared_auth/conf.py +33 -0
- shared_auth/decorators.py +122 -0
- shared_auth/exceptions.py +23 -0
- shared_auth/fields.py +51 -0
- shared_auth/management/__init__.py +0 -0
- shared_auth/management/commands/__init__.py +0 -0
- shared_auth/management/commands/generate_permissions.py +147 -0
- shared_auth/managers.py +344 -0
- shared_auth/middleware.py +281 -0
- shared_auth/mixins.py +475 -0
- shared_auth/models.py +191 -0
- shared_auth/permissions.py +266 -0
- shared_auth/permissions_cache.py +249 -0
- shared_auth/permissions_helpers.py +251 -0
- shared_auth/router.py +22 -0
- shared_auth/serializers.py +439 -0
- shared_auth/storage_backend.py +6 -0
- shared_auth/urls.py +8 -0
- shared_auth/utils.py +356 -0
- shared_auth/views.py +40 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Permissões customizadas para DRF
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from rest_framework import permissions
|
|
6
|
+
|
|
7
|
+
from shared_auth.middleware import get_member
|
|
8
|
+
from shared_auth.utils import get_organization_model
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class IsAuthenticated(permissions.BasePermission):
|
|
12
|
+
"""
|
|
13
|
+
Verifica se usuário está autenticado via SharedToken
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
message = "Autenticação necessária."
|
|
17
|
+
|
|
18
|
+
def has_permission(self, request, view):
|
|
19
|
+
return bool(
|
|
20
|
+
request.user and hasattr(request.user, "pk") and request.user.is_active
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class HasActiveOrganization(permissions.BasePermission):
|
|
25
|
+
"""
|
|
26
|
+
Verifica se usuário tem organização ativa
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
message = "Organização ativa necessária."
|
|
30
|
+
|
|
31
|
+
def has_permission(self, request, view):
|
|
32
|
+
if not request.user or not hasattr(request, "organization_id"):
|
|
33
|
+
return False
|
|
34
|
+
|
|
35
|
+
if not request.organization_id:
|
|
36
|
+
return False
|
|
37
|
+
|
|
38
|
+
# Verificar se organização está ativa
|
|
39
|
+
Organization = get_organization_model()
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
org = Organization.objects.get(pk=request.organization_id)
|
|
43
|
+
return org.is_active()
|
|
44
|
+
except Organization.DoesNotExist:
|
|
45
|
+
return False
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class IsSameOrganization(permissions.BasePermission):
|
|
49
|
+
"""
|
|
50
|
+
Verifica se o objeto pertence à mesma organização do usuário
|
|
51
|
+
|
|
52
|
+
O model deve ter organization_id
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
message = "Você não tem permissão para acessar este recurso."
|
|
56
|
+
|
|
57
|
+
def has_object_permission(self, request, view, obj):
|
|
58
|
+
if not hasattr(request, "organization_id"):
|
|
59
|
+
return False
|
|
60
|
+
|
|
61
|
+
if not hasattr(obj, "organization_id"):
|
|
62
|
+
return True # Se objeto não tem org, permite
|
|
63
|
+
|
|
64
|
+
# Verifica se o usuário é membro da organização do objeto
|
|
65
|
+
if not get_member(request.user.pk, obj.organization_id):
|
|
66
|
+
return False
|
|
67
|
+
|
|
68
|
+
return obj.organization_id == request.organization_id
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class IsOwnerOrSameOrganization(permissions.BasePermission):
|
|
72
|
+
"""
|
|
73
|
+
Verifica se é o dono do objeto OU da mesma organização
|
|
74
|
+
|
|
75
|
+
O model deve ter user_id e/ou organization_id
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
message = "Você não tem permissão para acessar este recurso."
|
|
79
|
+
|
|
80
|
+
def has_object_permission(self, request, view, obj):
|
|
81
|
+
# Verificar se é o dono
|
|
82
|
+
if hasattr(obj, "user_id") and obj.user_id == request.user.pk:
|
|
83
|
+
return True
|
|
84
|
+
|
|
85
|
+
# Verificar se é da mesma organização
|
|
86
|
+
if hasattr(obj, "organization_id") and hasattr(request, "organization_id"):
|
|
87
|
+
# Verifica se o usuário é membro da organização do objeto
|
|
88
|
+
if get_member(request.user.pk, obj.organization_id):
|
|
89
|
+
return obj.organization_id == request.organization_id
|
|
90
|
+
|
|
91
|
+
return False
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class HasSystemPermission(permissions.BasePermission):
|
|
95
|
+
"""
|
|
96
|
+
Verifica se usuário tem permissão específica no sistema.
|
|
97
|
+
|
|
98
|
+
Usage:
|
|
99
|
+
class MyViewSet(viewsets.ModelViewSet):
|
|
100
|
+
permission_classes = [HasSystemPermission]
|
|
101
|
+
required_permission = 'create_invoices'
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
message = "Você não tem permissão para realizar esta ação."
|
|
105
|
+
|
|
106
|
+
def has_permission(self, request, view):
|
|
107
|
+
"""Verifica permissão no nível da view"""
|
|
108
|
+
from django.conf import settings
|
|
109
|
+
from shared_auth.permissions_helpers import user_has_permission
|
|
110
|
+
|
|
111
|
+
# Pegar permissão requerida
|
|
112
|
+
permission_codename = getattr(view, 'required_permission', None)
|
|
113
|
+
|
|
114
|
+
if not permission_codename:
|
|
115
|
+
# Se não tem permissão definida, permite
|
|
116
|
+
return True
|
|
117
|
+
|
|
118
|
+
# Verificar autenticação
|
|
119
|
+
if not request.user or not request.user.is_authenticated:
|
|
120
|
+
return False
|
|
121
|
+
|
|
122
|
+
# Pegar organização
|
|
123
|
+
organization_id = getattr(request, 'organization_id', None)
|
|
124
|
+
if not organization_id:
|
|
125
|
+
return False
|
|
126
|
+
|
|
127
|
+
# Pegar sistema
|
|
128
|
+
system_id = getattr(settings, 'SYSTEM_ID', None)
|
|
129
|
+
if not system_id:
|
|
130
|
+
# Tentar pegar do header
|
|
131
|
+
header_value = request.headers.get('X-System-ID')
|
|
132
|
+
if header_value:
|
|
133
|
+
try:
|
|
134
|
+
system_id = int(header_value)
|
|
135
|
+
except (ValueError, TypeError):
|
|
136
|
+
return False
|
|
137
|
+
else:
|
|
138
|
+
return False
|
|
139
|
+
|
|
140
|
+
# Verificar permissão
|
|
141
|
+
return user_has_permission(
|
|
142
|
+
request.user.id,
|
|
143
|
+
organization_id,
|
|
144
|
+
permission_codename,
|
|
145
|
+
system_id,
|
|
146
|
+
request=request
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class HasAnyPermission(permissions.BasePermission):
|
|
151
|
+
"""
|
|
152
|
+
Verifica se usuário tem pelo menos uma das permissões.
|
|
153
|
+
|
|
154
|
+
Usage:
|
|
155
|
+
class MyViewSet(viewsets.ModelViewSet):
|
|
156
|
+
permission_classes = [HasAnyPermission]
|
|
157
|
+
required_permissions = ['view_reports', 'create_reports']
|
|
158
|
+
"""
|
|
159
|
+
|
|
160
|
+
message = "Você não tem nenhuma das permissões necessárias."
|
|
161
|
+
|
|
162
|
+
def has_permission(self, request, view):
|
|
163
|
+
"""Verifica se tem pelo menos uma permissão"""
|
|
164
|
+
from django.conf import settings
|
|
165
|
+
from shared_auth.permissions_helpers import user_has_permission
|
|
166
|
+
|
|
167
|
+
# Pegar permissões requeridas
|
|
168
|
+
permission_codenames = getattr(view, 'required_permissions', [])
|
|
169
|
+
|
|
170
|
+
if not permission_codenames:
|
|
171
|
+
# Se não tem permissões definidas, permite
|
|
172
|
+
return True
|
|
173
|
+
|
|
174
|
+
# Verificar autenticação
|
|
175
|
+
if not request.user or not request.user.is_authenticated:
|
|
176
|
+
return False
|
|
177
|
+
|
|
178
|
+
# Pegar organização
|
|
179
|
+
organization_id = getattr(request, 'organization_id', None)
|
|
180
|
+
if not organization_id:
|
|
181
|
+
return False
|
|
182
|
+
|
|
183
|
+
# Pegar sistema
|
|
184
|
+
system_id = getattr(settings, 'SYSTEM_ID', None)
|
|
185
|
+
if not system_id:
|
|
186
|
+
# Tentar pegar do header
|
|
187
|
+
header_value = request.headers.get('X-System-ID')
|
|
188
|
+
if header_value:
|
|
189
|
+
try:
|
|
190
|
+
system_id = int(header_value)
|
|
191
|
+
except (ValueError, TypeError):
|
|
192
|
+
return False
|
|
193
|
+
else:
|
|
194
|
+
return False
|
|
195
|
+
|
|
196
|
+
# Verificar se tem pelo menos uma permissão
|
|
197
|
+
return any(
|
|
198
|
+
user_has_permission(
|
|
199
|
+
request.user.id,
|
|
200
|
+
organization_id,
|
|
201
|
+
perm,
|
|
202
|
+
system_id,
|
|
203
|
+
request=request
|
|
204
|
+
)
|
|
205
|
+
for perm in permission_codenames
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class HasAllPermissions(permissions.BasePermission):
|
|
210
|
+
"""
|
|
211
|
+
Verifica se usuário tem todas as permissões.
|
|
212
|
+
|
|
213
|
+
Usage:
|
|
214
|
+
class MyViewSet(viewsets.ModelViewSet):
|
|
215
|
+
permission_classes = [HasAllPermissions]
|
|
216
|
+
required_permissions = ['create_invoices', 'edit_invoices']
|
|
217
|
+
"""
|
|
218
|
+
|
|
219
|
+
message = "Você não tem todas as permissões necessárias."
|
|
220
|
+
|
|
221
|
+
def has_permission(self, request, view):
|
|
222
|
+
"""Verifica se tem todas as permissões"""
|
|
223
|
+
from django.conf import settings
|
|
224
|
+
from shared_auth.permissions_helpers import user_has_permission
|
|
225
|
+
|
|
226
|
+
# Pegar permissões requeridas
|
|
227
|
+
permission_codenames = getattr(view, 'required_permissions', [])
|
|
228
|
+
|
|
229
|
+
if not permission_codenames:
|
|
230
|
+
# Se não tem permissões definidas, permite
|
|
231
|
+
return True
|
|
232
|
+
|
|
233
|
+
# Verificar autenticação
|
|
234
|
+
if not request.user or not request.user.is_authenticated:
|
|
235
|
+
return False
|
|
236
|
+
|
|
237
|
+
# Pegar organização
|
|
238
|
+
organization_id = getattr(request, 'organization_id', None)
|
|
239
|
+
if not organization_id:
|
|
240
|
+
return False
|
|
241
|
+
|
|
242
|
+
# Pegar sistema
|
|
243
|
+
system_id = getattr(settings, 'SYSTEM_ID', None)
|
|
244
|
+
if not system_id:
|
|
245
|
+
# Tentar pegar do header
|
|
246
|
+
header_value = request.headers.get('X-System-ID')
|
|
247
|
+
if header_value:
|
|
248
|
+
try:
|
|
249
|
+
system_id = int(header_value)
|
|
250
|
+
except (ValueError, TypeError):
|
|
251
|
+
return False
|
|
252
|
+
else:
|
|
253
|
+
return False
|
|
254
|
+
|
|
255
|
+
# Verificar se tem todas as permissões
|
|
256
|
+
return all(
|
|
257
|
+
user_has_permission(
|
|
258
|
+
request.user.id,
|
|
259
|
+
organization_id,
|
|
260
|
+
perm,
|
|
261
|
+
system_id,
|
|
262
|
+
request=request
|
|
263
|
+
)
|
|
264
|
+
for perm in permission_codenames
|
|
265
|
+
)
|
|
266
|
+
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Sistema de cache de permissões por request.
|
|
3
|
+
Elimina queries duplicadas durante verificação de permissões.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from threading import local
|
|
7
|
+
|
|
8
|
+
# Thread-local storage para cache quando não há request disponível
|
|
9
|
+
_thread_local = local()
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _get_cache_dict(request=None):
|
|
13
|
+
"""
|
|
14
|
+
Obtém o dicionário de cache de permissões.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
request: Request object (opcional)
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
dict: Dicionário de cache
|
|
21
|
+
"""
|
|
22
|
+
if request and hasattr(request, '_permissions_cache'):
|
|
23
|
+
return request._permissions_cache
|
|
24
|
+
|
|
25
|
+
# Fallback para thread-local (útil em contextos sem request)
|
|
26
|
+
if not hasattr(_thread_local, 'permissions_cache'):
|
|
27
|
+
_thread_local.permissions_cache = {}
|
|
28
|
+
return _thread_local.permissions_cache
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def get_cached_member(user_id, organization_id, request=None):
|
|
32
|
+
"""
|
|
33
|
+
Busca e cacheia Member para o par (user_id, organization_id).
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
user_id: ID do usuário
|
|
37
|
+
organization_id: ID da organização
|
|
38
|
+
request: Request object (opcional)
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
Member instance ou None
|
|
42
|
+
"""
|
|
43
|
+
from .utils import get_member_model
|
|
44
|
+
|
|
45
|
+
cache = _get_cache_dict(request)
|
|
46
|
+
cache_key = f'member_{user_id}_{organization_id}'
|
|
47
|
+
|
|
48
|
+
if cache_key in cache:
|
|
49
|
+
return cache[cache_key]
|
|
50
|
+
|
|
51
|
+
Member = get_member_model()
|
|
52
|
+
member = Member.objects.filter(
|
|
53
|
+
user_id=user_id,
|
|
54
|
+
organization_id=organization_id
|
|
55
|
+
).first()
|
|
56
|
+
|
|
57
|
+
cache[cache_key] = member
|
|
58
|
+
return member
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def get_cached_member_group(member_id, system_id, request=None):
|
|
62
|
+
"""
|
|
63
|
+
Busca e cacheia MemberSystemGroup para o par (member_id, system_id).
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
member_id: ID do membro
|
|
67
|
+
system_id: ID do sistema
|
|
68
|
+
request: Request object (opcional)
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
MemberSystemGroup instance ou None
|
|
72
|
+
"""
|
|
73
|
+
from .utils import get_member_system_group_model
|
|
74
|
+
|
|
75
|
+
cache = _get_cache_dict(request)
|
|
76
|
+
cache_key = f'member_group_{member_id}_{system_id}'
|
|
77
|
+
|
|
78
|
+
if cache_key in cache:
|
|
79
|
+
return cache[cache_key]
|
|
80
|
+
|
|
81
|
+
MemberSystemGroup = get_member_system_group_model()
|
|
82
|
+
member_group = MemberSystemGroup.objects.get_group_for_member_and_system(
|
|
83
|
+
member_id,
|
|
84
|
+
system_id
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
cache[cache_key] = member_group
|
|
88
|
+
return member_group
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def get_cached_group_permissions(group_id, system_id, request=None):
|
|
92
|
+
"""
|
|
93
|
+
Busca e cacheia GroupOrganizationPermissions com suas permissões.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
group_id: ID do grupo de permissões
|
|
97
|
+
system_id: ID do sistema
|
|
98
|
+
request: Request object (opcional)
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
GroupOrganizationPermissions instance ou None
|
|
102
|
+
"""
|
|
103
|
+
from .utils import get_group_organization_permissions_model
|
|
104
|
+
|
|
105
|
+
cache = _get_cache_dict(request)
|
|
106
|
+
cache_key = f'group_perms_{group_id}_{system_id}'
|
|
107
|
+
|
|
108
|
+
if cache_key in cache:
|
|
109
|
+
return cache[cache_key]
|
|
110
|
+
|
|
111
|
+
GroupOrgPermissions = get_group_organization_permissions_model()
|
|
112
|
+
try:
|
|
113
|
+
# Busca o grupo sem prefetch ainda
|
|
114
|
+
group = GroupOrgPermissions.objects.get(pk=group_id)
|
|
115
|
+
except GroupOrgPermissions.DoesNotExist:
|
|
116
|
+
cache[cache_key] = None
|
|
117
|
+
return None
|
|
118
|
+
|
|
119
|
+
cache[cache_key] = group
|
|
120
|
+
return group
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def get_cached_permission_codenames(group_id, system_id, request=None):
|
|
124
|
+
"""
|
|
125
|
+
Busca e cacheia SET de codenames de permissões do grupo.
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
group_id: ID do grupo de permissões
|
|
129
|
+
system_id: ID do sistema
|
|
130
|
+
request: Request object (opcional)
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
set: Set de codenames de permissões
|
|
134
|
+
"""
|
|
135
|
+
cache = _get_cache_dict(request)
|
|
136
|
+
cache_key = f'perm_codenames_{group_id}_{system_id}'
|
|
137
|
+
|
|
138
|
+
if cache_key in cache:
|
|
139
|
+
return cache[cache_key]
|
|
140
|
+
|
|
141
|
+
group = get_cached_group_permissions(group_id, system_id, request)
|
|
142
|
+
if not group:
|
|
143
|
+
cache[cache_key] = set()
|
|
144
|
+
return set()
|
|
145
|
+
|
|
146
|
+
# Buscar todos os codenames de uma vez
|
|
147
|
+
codenames = set(
|
|
148
|
+
group.permissions.filter(system_id=system_id)
|
|
149
|
+
.values_list('codename', flat=True)
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
cache[cache_key] = codenames
|
|
153
|
+
return codenames
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def get_cached_all_permissions(group_id, system_id, request=None):
|
|
157
|
+
"""
|
|
158
|
+
Busca e cacheia lista de Permission objects do grupo.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
group_id: ID do grupo de permissões
|
|
162
|
+
system_id: ID do sistema
|
|
163
|
+
request: Request object (opcional)
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
list: Lista de Permission objects
|
|
167
|
+
"""
|
|
168
|
+
cache = _get_cache_dict(request)
|
|
169
|
+
cache_key = f'all_perms_{group_id}_{system_id}'
|
|
170
|
+
|
|
171
|
+
if cache_key in cache:
|
|
172
|
+
return cache[cache_key]
|
|
173
|
+
|
|
174
|
+
group = get_cached_group_permissions(group_id, system_id, request)
|
|
175
|
+
if not group:
|
|
176
|
+
cache[cache_key] = []
|
|
177
|
+
return []
|
|
178
|
+
|
|
179
|
+
# Buscar todas as permissões de uma vez e converter para lista
|
|
180
|
+
permissions = list(group.permissions.filter(system_id=system_id))
|
|
181
|
+
|
|
182
|
+
cache[cache_key] = permissions
|
|
183
|
+
return permissions
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def warmup_permissions_cache(user_id, organization_id, system_id, request=None):
|
|
187
|
+
"""
|
|
188
|
+
Pré-carrega (warm-up) todas as permissões do usuário no cache.
|
|
189
|
+
Reduz 4 queries para apenas as necessárias no início da request.
|
|
190
|
+
|
|
191
|
+
Esta função deve ser chamada pelo middleware após autenticação.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
user_id: ID do usuário
|
|
195
|
+
organization_id: ID da organização
|
|
196
|
+
system_id: ID do sistema
|
|
197
|
+
request: Request object
|
|
198
|
+
|
|
199
|
+
Returns:
|
|
200
|
+
bool: True se conseguiu fazer warm-up, False caso contrário
|
|
201
|
+
"""
|
|
202
|
+
# 1. Buscar e cachear member
|
|
203
|
+
member = get_cached_member(user_id, organization_id, request)
|
|
204
|
+
if not member:
|
|
205
|
+
return False
|
|
206
|
+
|
|
207
|
+
# 2. Buscar e cachear member group
|
|
208
|
+
member_group = get_cached_member_group(member.id, system_id, request)
|
|
209
|
+
if not member_group:
|
|
210
|
+
return False
|
|
211
|
+
|
|
212
|
+
# 3. Buscar e cachear group permissions
|
|
213
|
+
group = get_cached_group_permissions(member_group.group_id, system_id, request)
|
|
214
|
+
if not group:
|
|
215
|
+
return False
|
|
216
|
+
|
|
217
|
+
# 4. OTIMIZAÇÃO PRINCIPAL: Carregar TODAS as permissões e codenames de uma vez
|
|
218
|
+
# Isso faz com que verificações subsequentes sejam O(1) em memória
|
|
219
|
+
get_cached_permission_codenames(member_group.group_id, system_id, request)
|
|
220
|
+
get_cached_all_permissions(member_group.group_id, system_id, request)
|
|
221
|
+
|
|
222
|
+
return True
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def clear_permissions_cache(request=None):
|
|
226
|
+
"""
|
|
227
|
+
Limpa o cache de permissões.
|
|
228
|
+
Útil para testes ou quando necessário forçar reload.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
request: Request object (opcional)
|
|
232
|
+
"""
|
|
233
|
+
if request and hasattr(request, '_permissions_cache'):
|
|
234
|
+
request._permissions_cache.clear()
|
|
235
|
+
|
|
236
|
+
if hasattr(_thread_local, 'permissions_cache'):
|
|
237
|
+
_thread_local.permissions_cache.clear()
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def init_permissions_cache(request):
|
|
241
|
+
"""
|
|
242
|
+
Inicializa o cache de permissões no request.
|
|
243
|
+
Chamado pelo middleware no início de cada request.
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
request: Request object
|
|
247
|
+
"""
|
|
248
|
+
if not hasattr(request, '_permissions_cache'):
|
|
249
|
+
request._permissions_cache = {}
|