15
15
from __future__ import annotations
16
16
17
17
from os import environ
18
- from typing import List , Union
18
+ from typing import List , Union , Optional , Dict , Any , Set
19
19
20
20
from supertokens_python .exceptions import SuperTokensError , raise_general_exception
21
21
from supertokens_python .framework import BaseRequest , BaseResponse
29
29
from supertokens_python .supertokens import AppInfo
30
30
31
31
from .exceptions import SuperTokensUserRolesError
32
+ from .interfaces import GetPermissionsForRoleOkResult
32
33
from .utils import InputOverrideConfig
34
+ from ..session import SessionRecipe
35
+ from ..session .claim_base_classes .primitive_array_claim import PrimitiveArrayClaim
36
+ from ...post_init_callbacks import PostSTInitCallbacks
33
37
34
38
35
39
class UserRolesRecipe (RecipeModule ):
@@ -40,17 +44,35 @@ def __init__(
40
44
self ,
41
45
recipe_id : str ,
42
46
app_info : AppInfo ,
47
+ skip_adding_roles_to_access_token : Optional [bool ] = None ,
48
+ skip_adding_permissions_to_access_token : Optional [bool ] = None ,
43
49
override : Union [InputOverrideConfig , None ] = None ,
44
50
):
45
51
super ().__init__ (recipe_id , app_info )
46
- self .config = validate_and_normalise_user_input (self , app_info , override )
52
+ self .config = validate_and_normalise_user_input (
53
+ self ,
54
+ app_info ,
55
+ skip_adding_roles_to_access_token ,
56
+ skip_adding_permissions_to_access_token ,
57
+ override ,
58
+ )
47
59
recipe_implementation = RecipeImplementation (Querier .get_instance (recipe_id ))
48
60
self .recipe_implementation = (
49
61
recipe_implementation
50
62
if self .config .override .functions is None
51
63
else self .config .override .functions (recipe_implementation )
52
64
)
53
65
66
+ def callback ():
67
+ if self .config .skip_adding_roles_to_access_token is False :
68
+ SessionRecipe .get_instance ().add_claim_from_other_recipe (UserRoleClaim )
69
+ if self .config .skip_adding_permissions_to_access_token is False :
70
+ SessionRecipe .get_instance ().add_claim_from_other_recipe (
71
+ PermissionClaim
72
+ )
73
+
74
+ PostSTInitCallbacks .add_post_init_callback (callback )
75
+
54
76
def is_error_from_this_recipe_based_on_instance (self , err : Exception ) -> bool :
55
77
return isinstance (err , SuperTokensError ) and (
56
78
isinstance (err , SuperTokensUserRolesError )
@@ -78,11 +100,19 @@ def get_all_cors_headers(self) -> List[str]:
78
100
return []
79
101
80
102
@staticmethod
81
- def init (override : Union [InputOverrideConfig , None ] = None ):
103
+ def init (
104
+ skip_adding_roles_to_access_token : Optional [bool ] = None ,
105
+ skip_adding_permissions_to_access_token : Optional [bool ] = None ,
106
+ override : Union [InputOverrideConfig , None ] = None ,
107
+ ):
82
108
def func (app_info : AppInfo ):
83
109
if UserRolesRecipe .__instance is None :
84
110
UserRolesRecipe .__instance = UserRolesRecipe (
85
- UserRolesRecipe .recipe_id , app_info , override
111
+ UserRolesRecipe .recipe_id ,
112
+ app_info ,
113
+ skip_adding_roles_to_access_token ,
114
+ skip_adding_permissions_to_access_token ,
115
+ override ,
86
116
)
87
117
return UserRolesRecipe .__instance
88
118
raise Exception (
@@ -107,3 +137,52 @@ def get_instance() -> UserRolesRecipe:
107
137
raise_general_exception (
108
138
"Initialisation not done. Did you forget to call the SuperTokens.init or UserRoles.init function?"
109
139
)
140
+
141
+
142
+ class PermissionClaimClass (PrimitiveArrayClaim [List [str ]]):
143
+ def __init__ (self ) -> None :
144
+ key = "st-perm"
145
+
146
+ async def fetch_value (user_id : str , user_context : Dict [str , Any ]) -> List [str ]:
147
+ recipe = UserRolesRecipe .get_instance ()
148
+
149
+ user_roles = await recipe .recipe_implementation .get_roles_for_user (
150
+ user_id , user_context
151
+ )
152
+
153
+ user_permissions : Set [str ] = set ()
154
+
155
+ for role in user_roles .roles :
156
+ role_permissions = (
157
+ await recipe .recipe_implementation .get_permissions_for_role (
158
+ role , user_context
159
+ )
160
+ )
161
+
162
+ if isinstance (role_permissions , GetPermissionsForRoleOkResult ):
163
+ for permission in role_permissions .permissions :
164
+ user_permissions .add (permission )
165
+
166
+ return list (user_permissions )
167
+
168
+ super ().__init__ (key , fetch_value )
169
+
170
+
171
+ PermissionClaim = PermissionClaimClass ()
172
+
173
+
174
+ class UserRoleClaimClass (PrimitiveArrayClaim [List [str ]]):
175
+ def __init__ (self ) -> None :
176
+ key = "st-role"
177
+
178
+ async def fetch_value (user_id : str , user_context : Dict [str , Any ]) -> List [str ]:
179
+ recipe = UserRolesRecipe .get_instance ()
180
+ res = await recipe .recipe_implementation .get_roles_for_user (
181
+ user_id , user_context
182
+ )
183
+ return res .roles
184
+
185
+ super ().__init__ (key , fetch_value )
186
+
187
+
188
+ UserRoleClaim = UserRoleClaimClass ()
0 commit comments