Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add implicit filter #46

Open
duboisj-illuminate opened this issue Feb 4, 2021 · 2 comments
Open

Add implicit filter #46

duboisj-illuminate opened this issue Feb 4, 2021 · 2 comments

Comments

@duboisj-illuminate
Copy link

The filtration library seems very close to what's needed for authorization logic. We have an incoming JWT token and would like to do something like adding 'implicit' filters (sometimes with joins) on most objects based on whether the userid (or, for joins, the userid in a related object) is the same as what's in the JWT.

Is there a good way to write filters and then have them triggered even when the graphql query did not include a filter, i.e., to mark certain kinds of filters as 'implicit' and use those for authorization?

I'm new to both the library and graphql. I've looked around a bit here & elsewhere and seen a bit of discussion of auth, but so far I can't figure out whether this is a reasonable direction to head.

@ShantanuJoshi
Copy link

ShantanuJoshi commented Feb 8, 2021

Here's an example of how I solved this exact issue. Required extending the default class and utilizing it in my queries:

class AuthModifiedFilterableConnectionField(FilterableConnectionField):
    @classmethod
    def get_query(cls, model, info: 'ResolveInfo', sort=None, **args):
        """Standard get_query with filtering. Adds nulls last to the default filterable connection order-by"""
        query = get_query(model, info.context)
        # logic for auth that get's auth info from flask:
        user_details = _request_ctx_stack.top.current_user
        # removed proprietary logic for getting uuid but imagine that's here... 
        if hasattr(model, 'uuid'):
            query = query.filter(model.uuid==uuid)

        if sort is not None:
            if isinstance(sort, six.string_types):
                query = query.order_by(nullslast(sort.value))
            else:
                query = query.order_by(nullslast(*(col.value for col in sort)))

        request_filters = args.get(cls.filter_arg)
        if request_filters:
            filter_set = cls.get_filter_set(info)
            query = filter_set.filter(info, query, request_filters)

        return query

FYI in this case I also wanted to add nullslast to all my sorts hence the extra few lines modifying the sort behavior.

Finally here's how my class is utilized:

class AuthQuery(graphene.ObjectType):
        saved_locations = AuthModifiedFilterableConnectionField(SavedLocationsType.connection, filters=SavedLocationsFilter())

Where savedlocations type and filter are defined as such:

class SavedLocationsType(SQLAlchemyObjectType):
    class Meta:
        model = SavedLocations #sql alchemy mapping that's imported
        interfaces = (graphene.relay.Node,)


class SavedLocationsFilter(FilterSet):
    class Meta:
        model = SavedLocations  #sql alchemy mapping that's imported
        fields = {
            'uuid': [...],
        }

I thought it may be helpful to also show how to wrap a decorator in flask in a view function (since I couldn't find this anywhere when I had to implement it)

flask_api.add_url_rule('/graphql/authenticated', view_func=requires_auth(GraphQLView.as_view(
        'authgql',
        schema=graphene.Schema(query=AuthQuery),
        graphiql=True
    )))

Where here I have a decorator called requires_auth that validates auth headers for any incoming requests.

Hope this helps!!

@art1415926535
Copy link
Owner

Adding 'implicit' filters sounds like you need your own custom resolver. graphene-sqlalchemy-filters must be used for explicit filters for clients.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants