How can I make tornado web return 403 if current_user is None instead of redirect to login_url?

huangapple go评论54阅读模式
英文:

How can I make tornado web return 403 if current_user is None instead of redirect to login_url?

问题

以下是方法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

看起来似乎无法实现您想要的功能。当HTTP方法为GET且用户未登录时,Tornado将始终重定向到login_url而不仅仅返回403。您的理解是正确的吗?

英文:

Following is the implementation of method authenticated:

def authenticated(
        method: Callable[..., Optional[Awaitable[None]]]
    ) -&gt; Callable[..., Optional[Awaitable[None]]]:
        &quot;&quot;&quot;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 &lt;RequestHandler.get_login_url&gt;`.

        If you configure a login url with a query parameter, Tornado will
        assume you know what you&#39;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&#39;re logged in.
        &quot;&quot;&quot;

        @functools.wraps(method)
        def wrapper(  # type: ignore
            self: RequestHandler, *args, **kwargs
        ) -&gt; Optional[Awaitable[None]]:
            if not self.current_user:
                if self.request.method in (&quot;GET&quot;, &quot;HEAD&quot;):
                    url = self.get_login_url()
                    if &quot;?&quot; 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 += &quot;?&quot; + 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?

答案1

得分: 1

你可以在你的基础处理程序中覆盖获取用户的逻辑。

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

对于async目的,你可以这样做:

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)
英文:

You can override the logic of getting user in your Base Handler

class BaseHandler(RequestHandler):
    
    def get_current_user(self) -&gt; Any:
        &quot;&quot;&quot;Override to determine the current user from, e.g., a cookie.

        This method may not be a coroutine.
        &quot;&quot;&quot;
        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: &#39;SomeUserModel | None&#39; = None
    ...
    
    async def prepare(self):
        self._current_user = await self.your_async_func()
        if self._current_user is None:
            raise HTTPError(403)

huangapple
  • 本文由 发表于 2023年5月21日 23:52:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/76300735.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定