Sanic: (Question) Can i do something like flask's ctx_stack on sanic?

Created on 6 Mar 2017  ·  6Comments  ·  Source: sanic-org/sanic

Hi, this is gonna be a short question.

i was moving my flask project to sanic the last part was to implement a auth system
which in my case i used a decorator something like ↓ in flask.

def jwt_required(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        jwt_data = _decode_jwt_from_request(type='access')
        if jwt_data['type'] != 'access':
            raise WrongTokenError('Only access tokens can access this endpoint')

        blacklist_enabled = get_blacklist_enabled()
        if blacklist_enabled:
            check_if_token_revoked(jwt_data)

        ctx_stack.top.jwt = jwt_data
        return fn(*args, **kwargs)
    return wrapper

And something like

def get_jwt_identity():
    return get_raw_jwt().get('identity', {})

to get the identity of the user.

do you have any suggestion to this case? thanks.

Most helpful comment

We should add a page in the docs about building view decorators. tl;dr: yes, you can! Instead of dealing with global contexts, you just intercept the request from the handler method. You can add whatever attributes you want to the request object, which can be consumed inside the handler method. Here's an example:

def require_login():
    def decorator(f):
        @wraps(f)
        async def decorated_function(request, *args, **kwargs):
            # you can check against request here
            authorized = False

            if authorized:
                request['jwt'] = 'some_data'
                response = await f(request, *args, **kwargs)
                return response
            else:
                return json({'status': 'not_authorized'}, 403)
        return decorated_function
    return decorator


@app.route("/")
@require_login()
async def test(request):
    return json({"jwt": request['jwt']})

All 6 comments

We should add a page in the docs about building view decorators. tl;dr: yes, you can! Instead of dealing with global contexts, you just intercept the request from the handler method. You can add whatever attributes you want to the request object, which can be consumed inside the handler method. Here's an example:

def require_login():
    def decorator(f):
        @wraps(f)
        async def decorated_function(request, *args, **kwargs):
            # you can check against request here
            authorized = False

            if authorized:
                request['jwt'] = 'some_data'
                response = await f(request, *args, **kwargs)
                return response
            else:
                return json({'status': 'not_authorized'}, 403)
        return decorated_function
    return decorator


@app.route("/")
@require_login()
async def test(request):
    return json({"jwt": request['jwt']})

@subyraman Thanks for your great answer!

We should add a page in the docs about building view decorators.

I totally agree with that!
this is very helpful! Thank you! keep it up! <3 :D

Hmmm what exactly

authorized = False
if authorized:

does?
this makes authorized always false.

Flask get ctx from stack by current threading id or greenlet id, so we can always get ctx of current request since a thread or a greenlet can only handle one request(including internal redirect) at a time.
But sanic use uvloop, a thread can handle more than one request, so ctx in sanic need another way to differentiate one request from another.

Hmmm what exactly

authorized = False
if authorized:
does?
this makes authorized always false.

Yes, it's just psuedocode. You'd get the authenticated status from the request as you need.

@subyraman Thanks i've finally done the authentication!
Please close this issue if possible!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

davidtgq picture davidtgq  ·  3Comments

litelife picture litelife  ·  3Comments

olalonde picture olalonde  ·  3Comments

misakar picture misakar  ·  4Comments

jasonab picture jasonab  ·  3Comments