Pithikos / rest-framework-roles

Role-based permissions for Django and Django REST Framework
MIT License
62 stars 4 forks source link

Can't get it to work with browser #9

Closed MVKozlov closed 8 months ago

MVKozlov commented 8 months ago

django 5.0.3 djangorestframework 3.15.0 rest-framework-roles 1.0.4


def is_test(request, view):
    return True

ROLES = {
    # Django out-of-the-box
    'admin': is_admin,
    'user': is_user,
    'anon': is_anon,

    # Some custom role examples
    'test': is_test,
}

class UserProfileView(views.APIView):
    view_permissions = {
        'get': { 'test': True },
#        'options': { 'test': True },
    }
    def get(self, request: Request, format=None):
        """
        Return a current user.
        """
        serializer = UserSerializer(request.user, context={'request': request})
        return Response(data=serializer.data)

this code work well if launched from curl/powershell but return 403 from browser(restframework ui)

UserProfileView: Handler 'options' fired but no explicit permission found in 'view_permissions' for this handler. Denying access

If I add 'options' to view_permissions it report that Handler 'wrapped' fired

when I try to use it with ViewSet. it want all viewset handlers and again wrapped

there are some more modules, their presence may have an effect

Pithikos commented 8 months ago

I wonder if you have multiple authentication classes.. Maybe on the browser the session authentication is used, while with CURL a token or something else? And not sure about the class definition.. looks wrong.

MVKozlov commented 8 months ago

Sorry, my example looks wrong because it wrong. Just corrected it :) Yes, I have two authentication classes

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication'
    ),

From Powershell I try to simulate both Basic and Session authentications and both work well.

Sql log show that it get current session from db successfully, my code execute return Response(data=serializer.data) but after that I get 403 from browser every time

my logs:

(0.016) SELECT "django_session"."session_key", "django_session"."session_data", "django_session"."expire_date" FROM "django_session" WHERE ("django_session"."expire_date" > '2024-03-22 07:50:50.622820+00:00'::timestamptz AND "django_session"."session_key" = 'xx2g52drinvwzwzte0vzij2dkv6ey4vw') LIMIT 21; args=(datetime.datetime(2024, 3, 22, 7, 50, 50, 622820, tzinfo=datetime.timezone.utc), 'xx2g52drinvwzwzte0vzij2dkv6ey4vw'); alias=default
(0.000) SELECT "auth_user"."id", "auth_user"."password", "auth_user"."last_login", "auth_user"."is_superuser", "auth_user"."username", "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email", "auth_user"."is_staff", "auth_user"."is_active", "auth_user"."date_joined" FROM "auth_user" WHERE "auth_user"."id" = 1 LIMIT 21; args=(1,); alias=default    
(0.000) SELECT "django_content_type"."app_label", "auth_permission"."codename" FROM "auth_permission" INNER JOIN "django_content_type" ON ("auth_permission"."content_type_id" = "django_content_type"."id"); args=(); alias=default
(0.000) SELECT "django_content_type"."app_label", "auth_permission"."codename" FROM "auth_permission" INNER JOIN "django_content_type" ON ("auth_permission"."content_type_id" = "django_content_type"."id"); args=(); alias=default
(0.000) SELECT "auth_group"."id", "auth_group"."name" FROM "auth_group" INNER JOIN "auth_user_groups" ON ("auth_group"."id" = "auth_user_groups"."group_id") WHERE "auth_user_groups"."user_id" = 1; args=(1,); alias=default
(0.000) SELECT "auth_permission"."id", "auth_permission"."name", "auth_permission"."content_type_id", "auth_permission"."codename" FROM "auth_permission" INNER JOIN "auth_user_user_permissions" ON ("auth_permission"."id" = "auth_user_user_permissions"."permission_id") INNER JOIN "django_content_type" ON ("auth_permission"."content_type_id" = "django_content_type"."id") WHERE "auth_user_user_permissions"."user_id" = 1 ORDER BY "django_content_type"."app_label" ASC, "django_content_type"."model" ASC, "auth_permission"."codename" ASC; args=(1,); alias=default
UserProfileView: Handler 'options' fired but no explicit permission found in 'view_permissions' for this handler. Denying access
[22/Mar/2024 10:50:50] "GET /api/common/userprofile HTTP/1.1" 403 135

(0.000) SELECT "django_session"."session_key", "django_session"."session_data", "django_session"."expire_date" FROM "django_session" WHERE ("django_session"."expire_date" > '2024-03-22 07:50:55.695735+00:00'::timestamptz AND "django_session"."session_key" = 'f5zhybhh37gif1b3gcs32xdjaao8y03w') LIMIT 21; args=(datetime.datetime(2024, 3, 22, 7, 50, 55, 695735, tzinfo=datetime.timezone.utc), 'f5zhybhh37gif1b3gcs32xdjaao8y03w'); alias=default
(0.000) SELECT "auth_user"."id", "auth_user"."password", "auth_user"."last_login", "auth_user"."is_superuser", "auth_user"."username", "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email", "auth_user"."is_staff", "auth_user"."is_active", "auth_user"."date_joined" FROM "auth_user" WHERE "auth_user"."id" = 1 LIMIT 21; args=(1,); alias=default    
(0.000) SELECT "django_content_type"."app_label", "auth_permission"."codename" FROM "auth_permission" INNER JOIN "django_content_type" ON ("auth_permission"."content_type_id" = "django_content_type"."id"); args=(); alias=default
(0.000) SELECT "django_content_type"."app_label", "auth_permission"."codename" FROM "auth_permission" INNER JOIN "django_content_type" ON ("auth_permission"."content_type_id" = "django_content_type"."id"); args=(); alias=default
(0.000) SELECT "auth_group"."id", "auth_group"."name" FROM "auth_group" INNER JOIN "auth_user_groups" ON ("auth_group"."id" = "auth_user_groups"."group_id") WHERE "auth_user_groups"."user_id" = 1; args=(1,); alias=default
(0.000) SELECT "auth_permission"."id", "auth_permission"."name", "auth_permission"."content_type_id", "auth_permission"."codename" FROM "auth_permission" INNER JOIN "auth_user_user_permissions" ON ("auth_permission"."id" = "auth_user_user_permissions"."permission_id") INNER JOIN "django_content_type" ON ("auth_permission"."content_type_id" = "django_content_type"."id") WHERE "auth_user_user_permissions"."user_id" = 1 ORDER BY "django_content_type"."app_label" ASC, "django_content_type"."model" ASC, "auth_permission"."codename" ASC; args=(1,); alias=default
[22/Mar/2024 10:50:55] "GET /api/common/userprofile HTTP/1.1" 200 366

the logs differ only in the presence of a message from your library

I thought maybe debug_toolbar was to blame, but disabling it didn't change anything

Pithikos commented 8 months ago

@MVKozlov I think I managed to fix this and released a new version pip install rest-framework-roles==1.0.5

The issue was in the order of the checks under the hood since I actually didn't use APIView much when creating the library. It now should work as expected even with APIView.

NOTE you still have to use options since the browser always sends initially an OPTIONS request followed by GET. Curl only sends a GET request.

Please let me know if that solves the issue for you

MVKozlov commented 8 months ago

@Pithikos, thanks, now it works!