Session not work in middleware("request")

What I want to do is to protect the openapi docs in sanic-ext.So I add a session auth on app.middleware(“request”). Code is below

@app.middleware("request")
async def basic_auth(request:Request):
    print(request.path)
    if request.path.startswith(app.config["OAS_URL_PREFIX"]):
        is_auth = request.ctx.session.get("doc_auth",None)
        if not is_auth:
            return text("no auth doc")

but it seems the request.ctx don’t have session on it .error is below

[2022-10-22 20:56:33 +0800] [1964165] [DEBUG] Starting a process: Sanic-Server-0-0
[2022-10-22 20:56:33 +0800] [1964179] [INFO] Sanic Extensions:
[2022-10-22 20:56:33 +0800] [1964179] [INFO]   > injection [0 added]
[2022-10-22 20:56:33 +0800] [1964179] [INFO]   > openapi [http://0.0.0.0:8000/py/docs]
[2022-10-22 20:56:33 +0800] [1964179] [INFO]   > http
[2022-10-22 20:56:33 +0800] [1964179] [INFO]   > templating [jinja2==3.1.2]
[2022-10-22 20:56:34 +0800] [1964179] [INFO] Starting worker [1964179]
/py/docs/
[2022-10-22 20:56:36 +0800] [1964179] [ERROR] Exception occurred while handling uri: 'https://0.0.0.0:8000/py/docs/'
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/dist-packages/sanic/app.py", line 901, in handle_request
    response = await self._run_request_middleware(
  File "/usr/local/lib/python3.8/dist-packages/sanic/app.py", line 1071, in _run_request_middleware
    response = await response
  File "server.py", line 70, in basic_auth
    is_auth = request.ctx.session.get("doc_auth",None)
AttributeError: 'types.SimpleNamespace' object has no attribute 'session'

Is there any solution?
the token auth maybe a work way but i don’t want to use it

How/when are you adding the session object? Did you consider execution order

but no mater where the order palced the two middleware. It stll not work

I use Sanic-seeion .code like below

app = Sanic("gmweb")
Session(app)

@app.on_request
async def basic_auth(request:Request):
    ....

or

app = Sanic("gmweb")

@app.on_request
async def basic_auth(request:Request):
    ....

Session(app)

both not work . Is something I have miss

I have no idea what Session is. This is not a Sanic object. If you would like support, please provide more details.

It just a sanic extensions . See here https://github.com/xen/sanic_session.
As its documents . Session(app) is to init it

That is a problem with that lib. You’d have to take it up there. IIRC it is no longer maintained. It is likely a small fix because it is likely that it is using the old request model, but it is not a project associated with the SCO, and is not officially supported.

TBH, you really don’t need it, and are probably better off creating your own decorator and wrapper to handle session management.

Check this out that was recently posted on Discord: Discord

from typing import Dict, Any
from dataclasses import dataclass
from uuid import uuid4

import ujson
from aioredis import Redis
from sanic import Sanic, Request
from sanic_ext import Extend, Extension


SESSION_PREFIX_KEY = "SESSION:"


@dataclass
class Session:
    sid: str
    data: Dict[str, Any]
    redis: Redis

    @property
    def key(self):
        return SESSION_PREFIX_KEY + self.sid

    async def save(self, ttl=1200):
        await self.redis.setex(self.key, ttl, ujson.dumps(self.data))

    async def ping(self, ttl=1200):
        await self.redis.expire(self.key, ttl)

    async def clean(self):
        await self.redis.delete(self.key)


class SessionExtension(Extension):
    name = "session"

    def startup(self, bootstrap) -> None:
        self.app.middleware(self.get_session, "request")

    @staticmethod
    async def get_session(request: Request):
        sid = request.cookies.get("sid")
        redis = request.app.ctx.redis
        if not sid:
            session = Session(sid=str(uuid4()), data={}, redis=redis)
        else:
            value = await redis.get(SESSION_PREFIX_KEY + sid)
            if value:
                session = Session(sid=sid, data=ujson.loads(value), redis=redis)
                await session.ping()
            else:
                session = Session(sid=str(uuid4()), data={}, redis=redis)

        request.ctx.session = session


Extend.register(SessionExtension())
3 Likes