Following is the implementation of method authenticated:
def authenticated(
method: Callable[..., Optional[Awaitable[None]]]
) -> Callable[..., Optional[Awaitable[None]]]:
"""Decorate methods with this to require that the user be logged in.
If the user is not logged in, they will be redirected to the configured
`login url <RequestHandler.get_login_url>`.
If you configure a login url with a query parameter, Tornado will
assume you know what you're doing and use it as-is. If not, it
will add a `next` parameter so the login page knows where to send
you once you're logged in.
"""
@functools.wraps(method)
def wrapper( # type: ignore
self: RequestHandler, *args, **kwargs
) -> Optional[Awaitable[None]]:
if not self.current_user:
if self.request.method in ("GET", "HEAD"):
url = self.get_login_url()
if "?" not in url:
if urllib.parse.urlsplit(url).scheme:
# if login url is absolute, make next absolute too
next_url = self.request.full_url()
else:
assert self.request.uri is not None
next_url = self.request.uri
url += "?" + urlencode(dict(next=next_url))
self.redirect(url)
return None
raise HTTPError(403)
return method(self, *args, **kwargs)
return wrapper
Seems there is no way to achieve what I want. When http method is GET, and if user didn't login, tornado will always redirect to login_url instead of just return 403.
Am I correct?
You can override the logic of getting user in your Base Handler
class BaseHandler(RequestHandler):
def get_current_user(self) -> Any:
"""Override to determine the current user from, e.g., a cookie.
This method may not be a coroutine.
"""
user = self.your_func_of_getting_user()
if user is None:
raise HTTPError(403)
return user
for async
purposes you can do the next:
class BaseHandler(RequestHandler):
_current_user: 'SomeUserModel | None' = None
...
async def prepare(self):
self._current_user = await self.your_async_func()
if self._current_user is None:
raise HTTPError(403)