-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Troubles with Session Auth #81
Comments
@wmshort Piccolo Admin use SessionAuth. You can also try something like this. auth_middleware = partial(
AuthenticationMiddleware,
backend=SessionsAuthBackend(
auth_table=BaseUser,
session_table=SessionsBase,
admin_only=False,
),
)
app = FastAPI(docs_url=None)
app.mount("/docs/", swagger_ui(schema_url="../openapi.json"))
# login endpoint which which provide login form
app.mount(
path="/login/",
app=session_login(
auth_table=BaseUser,
session_table=SessionsBase,
redirect_to="/docs/",
),
)
@app.post("/logout/", tags=["Logout"])
async def logout(request: Request):
response = JSONResponse(
{
"message": "You are logged out",
},
status_code=200,
)
response.delete_cookie("id")
return response I hope this helps. |
Cool, thanks, I will tinker around with this! Maybe I am being daft, but how, in this example, do you hook up the Thanks again for your suggestions! |
@sinisaos Thanks for sharing that example. Here's some code from one of my apps which might also be helpful: import datetime
from fastapi import FastAPI
from piccolo_api.csrf.middleware import CSRFMiddleware
from piccolo_api.openapi.endpoints import swagger_ui
from piccolo_api.session_auth.endpoints import session_login, session_logout
from piccolo_api.session_auth.middleware import SessionsAuthBackend
from starlette.middleware import Middleware
from starlette.middleware.authentication import AuthenticationMiddleware
from starlette.routing import Route
app = FastAPI()
app.mount(
"/login/",
session_login(),
)
private_app = FastAPI(
routes=[
Route("/logout/", session_logout()),
],
middleware=[
Middleware(
AuthenticationMiddleware,
backend=SessionsAuthBackend(
increase_expiry=datetime.timedelta(minutes=30)
),
),
Middleware(CSRFMiddleware, allow_form_param=True),
],
docs_url=None,
redoc_url=None,
)
# The Swagger docs which come with FastAPI don't support CSRF middleware, so we mount
# a custom one which Piccolo provides (accessible at /private/docs):
private_app.mount("/docs/", swagger_ui(schema_url="/private/openapi.json"))
@private_app.get('/my-secret-endpoint/')
def my_endpoint():
# This is just a normal FastAPI endpoint, and is protected by Session Auth
pass
app.mount("/private/", private_app)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app) You'll notice that there's basically two FastAPI apps - a root one, which contains anything which should be publicly accessible (such as the login endpoint) and a child app, which contains anything which should be protected by Session Auth. |
@wmshort Yes. You need endpoints from |
Thanks, both, this really helped! The key was thinking about them as distinct apps and separating out the different endpoints. The only sticky thing remaining is that the |
@wmshort This happens because # your imports
from starlette.responses import JSONResponse
app = FastAPI(docs_url=None)
app.mount("/docs/", swagger_ui(schema_url="../openapi.json"))
@app.post("/logout/", tags=["Logout"])
async def logout(request: Request):
response = JSONResponse(
{
"message": "You are logged out",
},
status_code=200,
)
response.delete_cookie("id") # or response.delete_cookie("yourcookie")
return response |
Yeah, it only supports POST. I had a look at the docs, and this isn't mentioned, so needs adding. |
If you've got a HTML template, you can put something like this in to logout: <form action="/private/logout/" method="POST">
<!--
You need to get the CSRF token. The CSRF middleware adds it to the FastAPI / Starlette request,
so if you add the request to the Jinja context, you can access the CSRF token from the template.
Alternatively you can get the csrftoken from the cookie using jQuery or something.
-->
<input name="csrftoken" type="hidden" value="{{ request.scope.get('csrftoken') }}" />
<button>Logout</button>
</form> An example of adding the request to the Jinja context: async def my_endpoint(self, request: Request):
template = ENVIRONMENT.get_template("app.html.jinja")
content = template.render(request=request)
return HTMLResponse(content) |
Closing issue, as the last remaining question appears to be addressed by #82 |
I am struggling a bit with Piccolo's authentication systems. I have a FastAPI app and am wrapping it with Starlette's AuthenticationMiddleware, as hinted in the docs, with the joint SessionAuth and SecretTokenAuth providers. The secret token seems to be working alright; my API client won't get results without the correct header-cum-token. However whatever I do on the browser gives me "Auth failed for all backends". I can't get to the login endpoint, though this appears properly configured according to the docs. I tried 'allow unauthenticated' to see if this would loosen up the permissions, but even the FastAPI docs give me this error. Is there any robust example app with SessionAuth to see how everything should be organized?
The text was updated successfully, but these errors were encountered: