Giter VIP home page Giter VIP logo

Comments (16)

changhyun-an avatar changhyun-an commented on May 10, 2024 5

Not sure if this helps, but.. try adding an await statement

@api.get("", response=Test, auth=ApiKey())
async def test(request):
    await request.auth  <<<
    return 200, {"msg": "hello!"}

from django-ninja.

stinovlas avatar stinovlas commented on May 10, 2024 2

@vitalik I'd like to help with this. I don't understand what's wrong with #202 though. It seems that it's very similar to the code above plus taking care of async auth on not-async operation and vice versa. If I understand what needs to be changed compared to #202, I'd be happy to prepare PR with code, tests and docs changes.

One of the main reasons I chose django-ninja was it's support for async views and I'd like to broaden the async experience even further. Right now, I can't use built-in auth at all and I'm doomed to calling my async auth function in each view, which is repetitive and prone to errors.

from django-ninja.

maxmorlocke avatar maxmorlocke commented on May 10, 2024 2

For the full copypasta

@api.get("", response=Test, auth=ApiKey())
async def test(request):
    api_key = await request.auth
    if not api_key:
        raise AuthenticationError()
    return 200, {"msg": "hello!"}

from django-ninja.

Speedy1991 avatar Speedy1991 commented on May 10, 2024 2

Thanks @changhyun-an and @maxmorlocke!
I build a decorator from your code :) This should reduce some boilerplate in case of many endpoints

def await_auth(f):
    @functools.wraps(f)
    async def decorator(*args, **kwargs):
        auth = await args[0].auth  # args[0] is always the request instance injected from ninja
        if not auth :
            raise AuthenticationError()
        args[0].auth = auth
        return await f(*args, **kwargs)
    return decorator

Usage:

api = NinjaAPI(auth=ApiKey(), ...)

@api.post(...)
@await_auth
async def create(request, data: Input):
    ....

from django-ninja.

vitalik avatar vitalik commented on May 10, 2024 1

Yes, in nutshell this is the code I'm targeting for...
but there are few things to deal with - like if you have async auth, but not-async operation or vice-versa

from django-ninja.

bluedodecahedron avatar bluedodecahedron commented on May 10, 2024 1

Is there any chance for this issue to be resolved soon? I'm quite fond of django-ninja, it's just this issue that I find a bit unsettling.

from django-ninja.

vitalik avatar vitalik commented on May 10, 2024 1

@skokado

I tried async-auth with v1.0 beta2 but it didn't work, and I finally came across this issue...

could you provide your example code ?

from django-ninja.

vitalik avatar vitalik commented on May 10, 2024 1

@skokado please check with latest version

pip install django-ninja==1.0rc0

from django-ninja.

rednaks avatar rednaks commented on May 10, 2024

any news on this ?

from django-ninja.

alexg0mel avatar alexg0mel commented on May 10, 2024

Not sure if this helps, but.. try adding an await statement

@api.get("", response=Test, auth=ApiKey())
async def test(request):
    await request.auth  <<<
    return 200, {"msg": "hello!"}

ah, that's the magic of the event loop. Thank you, it really works.

from django-ninja.

GTorreil avatar GTorreil commented on May 10, 2024

While @changhyun-an 's answer works with a single authentication mechanism, I am having issues with multiple authentication classes.
I have a JWTAuth and an APITokenAuth. Using the await request.auth technqiue, if the first auth class returns None, the second is not tried and auth fails.
I could combine both authentication classes in one, but I prefer to keep them separate.
Does anyone have an idea about this ?

from django-ninja.

skokado avatar skokado commented on May 10, 2024

I tried async-auth with v1.0 beta2 but it didn't work, and I finally came across this issue...

I saw "async authentication fully supported on all layers" in the Release Note, but is the async-auth roadmap still in progress?
https://github.com/vitalik/django-ninja/releases/tag/v1.0b2

If so, I'd be very happy to mention that in the documentation, also link to this PR :)
Thank you

from django-ninja.

skokado avatar skokado commented on May 10, 2024

@vitalik Sorry 🙇 I was using 0.22.2, I broke my local environment without realizing.
It works as I expected with 1.0b2.

But one more, when failed Authentication caused by no token provided, then occurs 500 error
Here's my example code.

from ninja import NinjaAPI
from ninja.security import HttpBearer

api = NinjaAPI()


class MyAuth(HttpBearer):
    async def authenticate(self, request, token):
        if token == "secret":
            request.user = MyUser(id=1, name="Foo")
            return token
        return None


@api.get("/me", auth=MyAuth())
async def me_view(request):
    return {"hello": "world"}
curl -X 'GET' \
  'http://localhost:8000/me' \
  -H 'accept: */*'

Traceback:

Traceback (most recent call last):
  File "/home/skokado/workspace/django-ninja-tutorial/venv/lib/python3.11/site-packages/ninja/operation.py", line 304, in _run_authentication
    result = await callback(request)
             ^^^^^^^^^^^^^^^^^^^^^^^
TypeError: object NoneType can't be used in 'await' expression

It does not solve by registering @api.exception_handler
By incorrect token then can get 401 response

curl -X 'GET' \
  'http://localhost:8000/api/me' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer dummy'

# => {"detail": "Unauthorized"}

That does not occur when using sync-auth

from django-ninja.

skokado avatar skokado commented on May 10, 2024

@vitalik Works as expected, thank you for fixing.

from django-ninja.

skokado avatar skokado commented on May 10, 2024

@vitalik Sorry for repetitive, but I found new Warning in case non-empty token request at only first time.
It does not matter the authenticate attempt would be succeede or not.

Sample code is same as above #44 (comment)

$ curl -X 'GET' \
  'http://localhost:8000/api/me' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer secret'
/home/skokado/workspace/django-ninja/ninja/operation.py:311: RuntimeWarning: coroutine 'MyAuth.authenticate' was never awaited
  result = await callback(request)
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
{"hello": "world"}

At here, callback is called twice

result = callback(request)
if result is not None:
result = await callback(request)

from django-ninja.

skokado avatar skokado commented on May 10, 2024

Created a PR for this #44 (comment)

#916

from django-ninja.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.