Comments (6)
Here it is! 🎉 🍰 🚀
https://fastapi.tiangolo.com/tutorial/security/oauth2-scopes/
@mattlaue the problem is that you probably still want to read the token, at least at some point, to verify that it's valid.
But the new SecurityScopes
allows you to read the scopes in a dependency that can be used in other dependencies or path operations.
Those dependencies and path operations can declare their own required scopes. And the sub-dependency (that is probably reading the token and verifying it directly) can access all those required scopes from the dependants.
So, you can have a central point that checks and verifies all the scopes, and then in different path operations you can have Security
dependencies with different scopes, for example:
@app.get("/somepath1/")
def some_path_1(current_user: User = Security(get_current_user, scopes=["some", "scopes"])):
...
@app.get("/somepath2/")
def some_path_2(current_user: User = Security(get_current_user, scopes=["something", "different"])):
...
def other_dependency(current_user: User = Security(get_current_user, scopes=["subdependency", "required"])):
...
@app.get("/somepath3/")
def some_path_3(sub_dep = Depends(other_dependency), current_user: User = Security(get_current_user, scopes=["more"])):
...
from fastapi.
This is a good question, and it isn't clear to me either. The advanced dependencies page in the docs would seem to suggest a pattern where you create a callable class or higher-order-function initialised from a list of scopes with a dependency on Security, and use that to check scope, e.g.
class ScopeChecker:
def __init__(self, scopes):
self._scopes = scopes
def __call__(self, request: Request, token: str = Security(oauth2_scheme)):
token = validate_jwt_token(token) # proper validation goes here
if not token_has_required_scopes(token, self._scopes):
raise HTTPException(403, detail='Forbidden')
return token
but that either leads to a rather ugly syntax, or you have to create a global dep object for each set of scopes (!):
# either
@app.get('/')
async def root(request: Request, user: UserToken = Depends(ScopeChecker(['user']))):
# ...
# or
check_is_user = ScopeChecker(['user'])
@app.get('/')
async def root(request: Request, user: UserToken = Depends(check_is_user)):
# ...
Based on my (cursory) reading of fastapi.dependencies.utils
I've been subclassing Depends
for something roughly like the following:
class ScopedTo(Depends):
"""Dependency on particular scope.
"""
def __init__(self, *scopes) -> None:
super().__init__(self.__call__)
self._scopes = scopes
def __call__(self, request: Request, token: str = Security(oauth2_scheme)) -> TokenData:
"""Check scopes and return the current user.
"""
token = validate_jwt_token(token) # proper validation goes here
if not token_has_required_scopes(token, self._scopes):
raise HTTPException(403, detail='Forbidden')
return token
which can then be used like:
@app.get('/')
async def root(request: Request, user: UserToken = ScopedTo('user', 'root:read')):
# ...
But I'm not convinced that this is the best solution. I would welcome any clarification on this issue!
from fastapi.
Sorry for the delay guys.
You're right, currently, there's no way to access the scopes defined in a Security
inside of its dependency/security function. And it totally makes sense to be able to access them.
I'm thinking about implementing it as an additional parameter that you can declare in the security function, I imagine a class fastapi.security.Scopes
that has an attribute scopes
with the list of scopes declared.
So, you would define your dependency something like:
async def get_current_user(scopes: Scopes, token: str = Security(oauth2_scheme)):
for scope in scopes.scopes:
...
It has to be a predefined class instead of a plain list to be able to recognize it and solve it while solving the dependencies. But I think that would be the simplest/cleanest way to get the scopes inside your dependencies without breaking or compromising anything else.
Would that sound good for you?
from fastapi.
This implementation is almost exactly the same as what we implemented for our application. I'd suggest something like (if possible):
async def get_current_user(scopes: Scopes(Security(oauth2_scheme))):
for scope in scopes.scopes:
...
This way you don't have an unused parameter token
cluttering the function.
from fastapi.
I assume this is solved now, so I'll close this issue. But feel free to add more comments or create new issues.
from fastapi.
Is there any mechanism to overwrite security scopes?
I had 10 URL in a router:
router = Router(dependencies=[Security(XXXBearer(), scopes=["admin"])])
@router.post("/url1/")
def url1_func():
...
@router.post("/url2/")
def url2_func():
...
@router.post("/url3/")
def url2_func():
...
...
let's say, the url3's scopes only require ["user"]
,
how should I do?
@router.post("/url3/")
def url2_func(a = Security(XXXBearer(), scopes=["user"])):
# it did not work like this
# the require scopes were still ["admin"]
from fastapi.
Related Issues (20)
- No streaming interface can not support concurrency for two fastapi servers
- Using pydantic Json Type as Form data type doesn't work HOT 1
- Raw docstring (leading `r`) defeats form feed `\f` truncation HOT 3
- OpenAPI Example with multipart/form-data not showing up HOT 5
- [BUG] Using Nested Pydantic models and `params: MyModel = Depends()` forces OpenAPI docs GET methods to require a request body. HOT 6
- How to fix this bug? HOT 2
- [BUG] Upgrade python-mulipart==0.0.7 from low version fastapi upload file may be 400 HOT 4
- Use `RootModel` as query parameter HOT 2
- Context managers in `Depends` are broken after 0.106 HOT 17
- Middleware runs twice HOT 8
- Support for Pydantic deprecated fields HOT 1
- axios can't receive error response status code
- Potential footgun when using custom `Response(background=<Task()>)` in conjunction with injected `BackgroundTasks` - the custom response overwrites the tasks HOT 3
- lifespan
- Breaking change with path parameters when updating to pydantic>=2 from pydantic<2 HOT 1
- trying to live video stream using Fastapi
- Package on test.pypi.org is broken
- middleware type
- It throws an exception when I specify return Http status code
- When backend restart the frontend request a protected api cause an unhandle exception: Exception in ASGI application HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from fastapi.