mirror of https://github.com/tiangolo/fastapi.git
Merge 7ab80197c4 into 5420847d9f
This commit is contained in:
commit
60fa95ebf0
|
|
@ -106,7 +106,17 @@ Now we declare that the *path operation* for `/users/me/items/` requires the sco
|
|||
|
||||
For this, we import and use `Security` from `fastapi`.
|
||||
|
||||
You can use `Security` to declare dependencies (just like `Depends`), but `Security` also receives a parameter `scopes` with a list of scopes (strings).
|
||||
You can use `Security` to declare dependencies (just like `Depends`), but `Security` also receives a parameter `oauth_scopes` with a list of scopes (strings).
|
||||
|
||||
/// note
|
||||
|
||||
Before version 0.122.X, the name of this parameter was `scopes`.
|
||||
|
||||
In FastAPI 0.122.X, the `scopes` parameter was deprecated in favor of `oauth_scopes`
|
||||
to avoid confusing it with the `scope` parameter, which is used to specify when the exit code
|
||||
of dependencies with `yield` should run.
|
||||
|
||||
///
|
||||
|
||||
In this case, we pass a dependency function `get_current_active_user` to `Security` (the same way we would do with `Depends`).
|
||||
|
||||
|
|
@ -124,7 +134,7 @@ We are doing it here to demonstrate how **FastAPI** handles scopes declared at d
|
|||
|
||||
///
|
||||
|
||||
{* ../../docs_src/security/tutorial005_an_py310.py hl[5,141,172] *}
|
||||
{* ../../docs_src/security/tutorial005_an_py310.py hl[5,141,173] *}
|
||||
|
||||
/// info | Technical Details
|
||||
|
||||
|
|
@ -213,13 +223,13 @@ Here's how the hierarchy of dependencies and scopes looks like:
|
|||
* This `security_scopes` parameter has a property `scopes` with a `list` containing all these scopes declared above, so:
|
||||
* `security_scopes.scopes` will contain `["me", "items"]` for the *path operation* `read_own_items`.
|
||||
* `security_scopes.scopes` will contain `["me"]` for the *path operation* `read_users_me`, because it is declared in the dependency `get_current_active_user`.
|
||||
* `security_scopes.scopes` will contain `[]` (nothing) for the *path operation* `read_system_status`, because it didn't declare any `Security` with `scopes`, and its dependency, `get_current_user`, doesn't declare any `scopes` either.
|
||||
* `security_scopes.scopes` will contain `[]` (nothing) for the *path operation* `read_system_status`, because it didn't declare any `Security` with `oauth_scopes`, and its dependency, `get_current_user`, doesn't declare any `oauth_scopes` either.
|
||||
|
||||
/// tip
|
||||
|
||||
The important and "magic" thing here is that `get_current_user` will have a different list of `scopes` to check for each *path operation*.
|
||||
|
||||
All depending on the `scopes` declared in each *path operation* and each dependency in the dependency tree for that specific *path operation*.
|
||||
All depending on the `oauth_scopes` declared in each *path operation* and each dependency in the dependency tree for that specific *path operation*.
|
||||
|
||||
///
|
||||
|
||||
|
|
@ -271,4 +281,4 @@ But in the end, they are implementing the same OAuth2 standard.
|
|||
|
||||
## `Security` in decorator `dependencies` { #security-in-decorator-dependencies }
|
||||
|
||||
The same way you can define a `list` of `Depends` in the decorator's `dependencies` parameter (as explained in [Dependencies in path operation decorators](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}), you could also use `Security` with `scopes` there.
|
||||
The same way you can define a `list` of `Depends` in the decorator's `dependencies` parameter (as explained in [Dependencies in path operation decorators](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}), you could also use `Security` with `oauth_scopes` there.
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ async def get_current_user(
|
|||
|
||||
|
||||
async def get_current_active_user(
|
||||
current_user: Annotated[User, Security(get_current_user, scopes=["me"])],
|
||||
current_user: Annotated[User, Security(get_current_user, oauth_scopes=["me"])],
|
||||
):
|
||||
if current_user.disabled:
|
||||
raise HTTPException(status_code=400, detail="Inactive user")
|
||||
|
|
@ -172,7 +172,9 @@ async def read_users_me(
|
|||
|
||||
@app.get("/users/me/items/")
|
||||
async def read_own_items(
|
||||
current_user: Annotated[User, Security(get_current_active_user, scopes=["items"])],
|
||||
current_user: Annotated[
|
||||
User, Security(get_current_active_user, oauth_scopes=["items"])
|
||||
],
|
||||
):
|
||||
return [{"item_id": "Foo", "owner": current_user.username}]
|
||||
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ async def get_current_user(
|
|||
|
||||
|
||||
async def get_current_active_user(
|
||||
current_user: User = Security(get_current_user, scopes=["me"]),
|
||||
current_user: User = Security(get_current_user, oauth_scopes=["me"]),
|
||||
):
|
||||
if current_user.disabled:
|
||||
raise HTTPException(status_code=400, detail="Inactive user")
|
||||
|
|
@ -169,7 +169,7 @@ async def read_users_me(current_user: User = Depends(get_current_active_user)) -
|
|||
|
||||
@app.get("/users/me/items/")
|
||||
async def read_own_items(
|
||||
current_user: User = Security(get_current_active_user, scopes=["items"]),
|
||||
current_user: User = Security(get_current_active_user, oauth_scopes=["items"]),
|
||||
):
|
||||
return [{"item_id": "Foo", "owner": current_user.username}]
|
||||
|
||||
|
|
|
|||
|
|
@ -113,8 +113,8 @@ def get_parameterless_sub_dependant(*, depends: params.Depends, path: str) -> De
|
|||
"A parameter-less dependency must have a callable dependency"
|
||||
)
|
||||
own_oauth_scopes: list[str] = []
|
||||
if isinstance(depends, params.Security) and depends.scopes:
|
||||
own_oauth_scopes.extend(depends.scopes)
|
||||
if isinstance(depends, params.Security) and depends.oauth_scopes:
|
||||
own_oauth_scopes.extend(depends.oauth_scopes)
|
||||
return get_dependant(
|
||||
path=path,
|
||||
call=depends.dependency,
|
||||
|
|
@ -296,8 +296,8 @@ def get_dependant(
|
|||
)
|
||||
sub_own_oauth_scopes: list[str] = []
|
||||
if isinstance(param_details.depends, params.Security):
|
||||
if param_details.depends.scopes:
|
||||
sub_own_oauth_scopes = list(param_details.depends.scopes)
|
||||
if param_details.depends.oauth_scopes:
|
||||
sub_own_oauth_scopes = list(param_details.depends.oauth_scopes)
|
||||
sub_dependant = get_dependant(
|
||||
path=path,
|
||||
call=param_details.depends.dependency,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
from collections.abc import Callable, Sequence
|
||||
import warnings
|
||||
from collections.abc import Callable
|
||||
from typing import Annotated, Any, Literal
|
||||
|
||||
from annotated_doc import Doc
|
||||
from fastapi import params
|
||||
from fastapi._compat import Undefined
|
||||
from fastapi.exceptions import FastAPIError
|
||||
from fastapi.openapi.models import Example
|
||||
from pydantic import AliasChoices, AliasPath
|
||||
from typing_extensions import deprecated
|
||||
|
|
@ -2367,6 +2369,16 @@ def Depends( # noqa: N802
|
|||
return commons
|
||||
```
|
||||
"""
|
||||
|
||||
# Handle case when `scope` parameter value is invalid
|
||||
if scope not in ("function", "request", None):
|
||||
raise FastAPIError(
|
||||
"Invalid value for 'scope' parameter in Depends(). "
|
||||
"Expected 'function', 'request', or None. "
|
||||
f'Did you mean to use Security(dependency_fn, oauth_scopes="{scope}") '
|
||||
"to specify OAuth2 scopes instead?"
|
||||
)
|
||||
|
||||
return params.Depends(dependency=dependency, use_cache=use_cache, scope=scope)
|
||||
|
||||
|
||||
|
|
@ -2386,8 +2398,24 @@ def Security( # noqa: N802
|
|||
),
|
||||
] = None,
|
||||
*,
|
||||
oauth_scopes: Annotated[
|
||||
list[str] | tuple[str, ...] | set[str] | frozenset[str] | None,
|
||||
Doc(
|
||||
"""
|
||||
OAuth2 scopes required for the *path operation* that uses this Security
|
||||
dependency.
|
||||
|
||||
The term "scope" comes from the OAuth2 specification, it seems to be
|
||||
intentionally vague and interpretable. It normally refers to permissions,
|
||||
in cases to roles.
|
||||
|
||||
These scopes are integrated with OpenAPI (and the API docs at `/docs`).
|
||||
So they are visible in the OpenAPI specification.
|
||||
"""
|
||||
),
|
||||
] = None,
|
||||
scopes: Annotated[
|
||||
Sequence[str] | None,
|
||||
list[str] | tuple[str, ...] | set[str] | frozenset[str] | None,
|
||||
Doc(
|
||||
"""
|
||||
OAuth2 scopes required for the *path operation* that uses this Security
|
||||
|
|
@ -2402,6 +2430,48 @@ def Security( # noqa: N802
|
|||
|
||||
Read more about it in the
|
||||
[FastAPI docs about OAuth2 scopes](https://fastapi.tiangolo.com/advanced/security/oauth2-scopes/)
|
||||
|
||||
This parameter is deprecated in favor of `oauth_scopes`.
|
||||
"""
|
||||
),
|
||||
deprecated(
|
||||
"""
|
||||
In order to avoid confusion with `scope` parameter, the `scopes` parameter
|
||||
is deprecated in favor of `oauth_scopes`.
|
||||
|
||||
To specify dependency scope for dependencies with `yield` use `scope` parameter:
|
||||
|
||||
```python
|
||||
Security(dependency_fn, scope="function")
|
||||
```
|
||||
|
||||
To specify OAuth2 scopes use `oauth_scopes` parameter:
|
||||
|
||||
```python
|
||||
Security(dependency_fn, oauth_scopes=["items", "users"])
|
||||
```
|
||||
|
||||
​
|
||||
"""
|
||||
),
|
||||
] = None,
|
||||
scope: Annotated[
|
||||
Literal["function", "request"] | None,
|
||||
Doc(
|
||||
"""
|
||||
Mainly for dependencies with `yield`, define when the dependency function
|
||||
should start (the code before `yield`) and when it should end (the code
|
||||
after `yield`).
|
||||
|
||||
* `"function"`: start the dependency before the *path operation function*
|
||||
that handles the request, end the dependency after the *path operation
|
||||
function* ends, but **before** the response is sent back to the client.
|
||||
So, the dependency function will be executed **around** the *path operation
|
||||
**function***.
|
||||
* `"request"`: start the dependency before the *path operation function*
|
||||
that handles the request (similar to when using `"function"`), but end
|
||||
**after** the response is sent back to the client. So, the dependency
|
||||
function will be executed **around** the **request** and response cycle.
|
||||
"""
|
||||
),
|
||||
] = None,
|
||||
|
|
@ -2427,8 +2497,8 @@ def Security( # noqa: N802
|
|||
Declare a FastAPI Security dependency.
|
||||
|
||||
The only difference with a regular dependency is that it can declare OAuth2
|
||||
scopes that will be integrated with OpenAPI and the automatic UI docs (by default
|
||||
at `/docs`).
|
||||
scopes (`oauth_scopes` parameter) that will be integrated with OpenAPI and the
|
||||
automatic UI docs (by default at `/docs`).
|
||||
|
||||
It takes a single "dependable" callable (like a function).
|
||||
|
||||
|
|
@ -2453,9 +2523,58 @@ def Security( # noqa: N802
|
|||
|
||||
@app.get("/users/me/items/")
|
||||
async def read_own_items(
|
||||
current_user: Annotated[User, Security(get_current_active_user, scopes=["items"])]
|
||||
current_user: Annotated[
|
||||
User, Security(get_current_active_user, oauth_scopes=["items"])
|
||||
]
|
||||
):
|
||||
return [{"item_id": "Foo", "owner": current_user.username}]
|
||||
```
|
||||
"""
|
||||
return params.Security(dependency=dependency, scopes=scopes, use_cache=use_cache)
|
||||
|
||||
if scopes is not None:
|
||||
warnings.warn(
|
||||
(
|
||||
"The 'scopes' parameter in Security() is deprecated in favor of "
|
||||
"'oauth_scopes' in order to avoid confusion with 'scope' parameter."
|
||||
),
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
# Handle case when `scopes="function"` is mistakenly used instead of `scope="function"`
|
||||
if isinstance(scopes, str) and (scopes in ("function", "request")):
|
||||
raise FastAPIError(
|
||||
"Invalid value for the 'scopes' parameter in Security(). "
|
||||
"Expected a sequence of strings (e.g., ['admin', 'user']), but received "
|
||||
"a single string. "
|
||||
f'Did you mean to use scope="{scopes}" to specify when the exit code '
|
||||
"of dependencies with yield should run? "
|
||||
)
|
||||
|
||||
oauth_scopes_param = "oauth_scopes" if (oauth_scopes is not None) else "scopes"
|
||||
oauth_scopes = oauth_scopes or scopes
|
||||
|
||||
# Handle case when single string is passed to `scopes` or `oauth_scopes` instead of
|
||||
# a list of strings
|
||||
if isinstance(oauth_scopes, str):
|
||||
raise FastAPIError(
|
||||
f"Invalid value for the '{oauth_scopes_param}' parameter in Security(). "
|
||||
"Expected a sequence of strings (e.g., ['admin', 'user']), but received a "
|
||||
"single string. Wrap it in a list: oauth_scopes=['your_scope'] instead of "
|
||||
"oauth_scopes='your_scope'."
|
||||
)
|
||||
|
||||
# Handle case when `scope` parameter value is invalid
|
||||
if scope not in ("function", "request", None):
|
||||
raise FastAPIError(
|
||||
"Invalid value for 'scope' parameter in Security(). "
|
||||
"Expected 'function', 'request', or None. "
|
||||
f'Did you mean oauth_scopes="{scope}" to specify OAuth2 scopes instead?'
|
||||
)
|
||||
|
||||
return params.Security(
|
||||
dependency=dependency,
|
||||
oauth_scopes=oauth_scopes,
|
||||
use_cache=use_cache,
|
||||
scope=scope,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import warnings
|
||||
from collections.abc import Callable, Sequence
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
from typing import Annotated, Any, Literal
|
||||
|
|
@ -752,4 +752,4 @@ class Depends:
|
|||
|
||||
@dataclass(frozen=True)
|
||||
class Security(Depends):
|
||||
scopes: Sequence[str] | None = None
|
||||
oauth_scopes: list[str] | tuple[str, ...] | set[str] | frozenset[str] | None = None
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ async def get_sub_counter_no_cache(
|
|||
@app.get("/scope-counter")
|
||||
async def get_scope_counter(
|
||||
count: int = Security(dep_counter),
|
||||
scope_count_1: int = Security(dep_counter, scopes=["scope"]),
|
||||
scope_count_2: int = Security(dep_counter, scopes=["scope"]),
|
||||
scope_count_1: int = Security(dep_counter, oauth_scopes=["scope"]),
|
||||
scope_count_2: int = Security(dep_counter, oauth_scopes=["scope"]),
|
||||
):
|
||||
return {
|
||||
"counter": count,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Annotated, Union
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import FastAPI, HTTPException, Security
|
||||
from fastapi.security import (
|
||||
|
|
@ -13,7 +13,7 @@ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
|
|||
|
||||
|
||||
def process_auth(
|
||||
credentials: Annotated[Union[str, None], Security(oauth2_scheme)],
|
||||
credentials: Annotated[str | None, Security(oauth2_scheme)],
|
||||
security_scopes: SecurityScopes,
|
||||
):
|
||||
# This is an incorrect way of using it, this is not checking if the scopes are
|
||||
|
|
@ -27,14 +27,14 @@ def process_auth(
|
|||
|
||||
@app.get("/get-credentials")
|
||||
def get_credentials(
|
||||
credentials: Annotated[dict, Security(process_auth, scopes=["a", "b"])],
|
||||
credentials: Annotated[dict, Security(process_auth, oauth_scopes=["a", "b"])],
|
||||
):
|
||||
return credentials
|
||||
|
||||
|
||||
@app.get(
|
||||
"/parameterless-with-scopes",
|
||||
dependencies=[Security(process_auth, scopes=["a", "b"])],
|
||||
dependencies=[Security(process_auth, oauth_scopes=["a", "b"])],
|
||||
)
|
||||
def get_parameterless_with_scopes():
|
||||
return {"status": "ok"}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ def get_data_override():
|
|||
|
||||
@app.get("/user")
|
||||
def read_user(
|
||||
user_data: tuple[str, list[str]] = Security(get_user, scopes=["foo", "bar"]),
|
||||
user_data: tuple[str, list[str]] = Security(get_user, oauth_scopes=["foo", "bar"]),
|
||||
data: list[int] = Depends(get_data),
|
||||
):
|
||||
return {"user": user_data[0], "scopes": user_data[1], "data": data}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,84 @@
|
|||
import pytest
|
||||
from fastapi import Depends, Security
|
||||
from fastapi.exceptions import FastAPIError
|
||||
|
||||
|
||||
def test_scopes_deprecation_warning():
|
||||
"""
|
||||
Test that using `scopes` parameter raises a deprecation warning.
|
||||
"""
|
||||
|
||||
with pytest.warns(DeprecationWarning) as record:
|
||||
Security(dependency=lambda: None, scopes=["admin"])
|
||||
|
||||
assert len(record) == 1
|
||||
warning = record[0]
|
||||
assert issubclass(warning.category, DeprecationWarning)
|
||||
assert str(warning.message) == (
|
||||
"The 'scopes' parameter in Security() is deprecated in favor of "
|
||||
"'oauth_scopes' in order to avoid confusion with 'scope' parameter."
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("parameter_name", ["scopes", "oauth_scopes"])
|
||||
@pytest.mark.filterwarnings("ignore::DeprecationWarning")
|
||||
def test_pass_single_str(parameter_name: str):
|
||||
"""
|
||||
Test passing single string instead of list of strings to `scopes` or `oauth_scopes`.
|
||||
"""
|
||||
|
||||
with pytest.raises(FastAPIError) as exc_info:
|
||||
Security(dependency=lambda: None, **{parameter_name: "admin"})
|
||||
|
||||
assert str(exc_info.value) == (
|
||||
f"Invalid value for the '{parameter_name}' parameter in Security(). "
|
||||
"Expected a sequence of strings (e.g., ['admin', 'user']), but received a single string. "
|
||||
"Wrap it in a list: oauth_scopes=['your_scope'] instead of oauth_scopes='your_scope'."
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", ["function", "request"])
|
||||
@pytest.mark.filterwarnings("ignore::DeprecationWarning")
|
||||
def test_pass_scope_as_scopes(value: str):
|
||||
"""
|
||||
Test passing `scopes="function"` instead of `scope="function"` to `Security`.
|
||||
"""
|
||||
|
||||
with pytest.raises(FastAPIError) as exc_info:
|
||||
Security(dependency=lambda: None, scopes=value)
|
||||
|
||||
assert str(exc_info.value) == (
|
||||
"Invalid value for the 'scopes' parameter in Security(). "
|
||||
"Expected a sequence of strings (e.g., ['admin', 'user']), but received a single string. "
|
||||
f'Did you mean to use scope="{value}" to specify when the exit code of dependencies with yield should run? '
|
||||
)
|
||||
|
||||
|
||||
def test_pass_invalid_scope_value_to_security():
|
||||
"""
|
||||
Test passing invalid value to `scope` parameter in `Security`.
|
||||
"""
|
||||
|
||||
with pytest.raises(FastAPIError) as exc_info:
|
||||
Security(dependency=lambda: None, scope="invalid_scope")
|
||||
|
||||
assert str(exc_info.value) == (
|
||||
"Invalid value for 'scope' parameter in Security(). "
|
||||
"Expected 'function', 'request', or None. "
|
||||
'Did you mean oauth_scopes="invalid_scope" to specify OAuth2 scopes instead?'
|
||||
)
|
||||
|
||||
|
||||
def test_pass_invalid_scope_value_to_depends():
|
||||
"""
|
||||
Test passing invalid value to `scope` parameter in `Depends`.
|
||||
"""
|
||||
|
||||
with pytest.raises(FastAPIError) as exc_info:
|
||||
Depends(dependency=lambda: None, scope="invalid_scope")
|
||||
|
||||
assert str(exc_info.value) == (
|
||||
"Invalid value for 'scope' parameter in Depends(). "
|
||||
"Expected 'function', 'request', or None. "
|
||||
'Did you mean to use Security(dependency_fn, oauth_scopes="invalid_scope") to specify OAuth2 scopes instead?'
|
||||
)
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
# Ref: https://github.com/fastapi/fastapi/issues/14454
|
||||
|
||||
from typing import Annotated, Optional
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Depends, FastAPI, Security
|
||||
from fastapi.security import OAuth2AuthorizationCodeBearer
|
||||
|
|
@ -29,30 +29,31 @@ async def root():
|
|||
|
||||
@app.get(
|
||||
"/with-oauth2-scheme",
|
||||
dependencies=[Security(oauth2_scheme, scopes=["read", "write"])],
|
||||
dependencies=[Security(oauth2_scheme, oauth_scopes=["read", "write"])],
|
||||
)
|
||||
async def read_with_oauth2_scheme():
|
||||
return {"message": "Admin Access"}
|
||||
|
||||
|
||||
@app.get(
|
||||
"/with-get-token", dependencies=[Security(get_token, scopes=["read", "write"])]
|
||||
"/with-get-token",
|
||||
dependencies=[Security(get_token, oauth_scopes=["read", "write"])],
|
||||
)
|
||||
async def read_with_get_token():
|
||||
return {"message": "Admin Access"}
|
||||
|
||||
|
||||
router = APIRouter(dependencies=[Security(oauth2_scheme, scopes=["read"])])
|
||||
router = APIRouter(dependencies=[Security(oauth2_scheme, oauth_scopes=["read"])])
|
||||
|
||||
|
||||
@router.get("/items/")
|
||||
async def read_items(token: Optional[str] = Depends(oauth2_scheme)):
|
||||
async def read_items(token: str | None = Depends(oauth2_scheme)):
|
||||
return {"token": token}
|
||||
|
||||
|
||||
@router.post("/items/")
|
||||
async def create_item(
|
||||
token: Optional[str] = Security(oauth2_scheme, scopes=["read", "write"]),
|
||||
token: str | None = Security(oauth2_scheme, oauth_scopes=["read", "write"]),
|
||||
):
|
||||
return {"token": token}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ async def get_token(token: Annotated[str, Depends(oauth2_scheme)]) -> str:
|
|||
app = FastAPI(dependencies=[Depends(get_token)])
|
||||
|
||||
|
||||
@app.get("/admin", dependencies=[Security(get_token, scopes=["read", "write"])])
|
||||
@app.get("/admin", dependencies=[Security(get_token, oauth_scopes=["read", "write"])])
|
||||
async def read_admin():
|
||||
return {"message": "Admin Access"}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ def app_fixture(call_counter: dict[str, int]):
|
|||
@app.get("/")
|
||||
def endpoint(
|
||||
db: Annotated[str, Depends(get_db)],
|
||||
user: Annotated[str, Security(get_user, scopes=["read"])],
|
||||
user: Annotated[str, Security(get_user, oauth_scopes=["read"])],
|
||||
):
|
||||
return {"db": db}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ async def security2(scopes: SecurityScopes):
|
|||
|
||||
|
||||
async def dep3(
|
||||
dep1: Annotated[list[str], Security(security1, scopes=["scope1"])],
|
||||
dep2: Annotated[list[str], Security(security2, scopes=["scope2"])],
|
||||
dep1: Annotated[list[str], Security(security1, oauth_scopes=["scope1"])],
|
||||
dep2: Annotated[list[str], Security(security2, oauth_scopes=["scope2"])],
|
||||
):
|
||||
return {"dep1": dep1, "dep2": dep2}
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ app = FastAPI()
|
|||
|
||||
@app.get("/scopes")
|
||||
def get_scopes(
|
||||
dep3: Annotated[dict[str, Any], Security(dep3, scopes=["scope3"])],
|
||||
dep3: Annotated[dict[str, Any], Security(dep3, oauth_scopes=["scope3"])],
|
||||
):
|
||||
return dep3
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ def app_fixture(call_counts: dict[str, int]):
|
|||
}
|
||||
|
||||
def get_user_me(
|
||||
current_user: Annotated[dict, Security(get_current_user, scopes=["me"])],
|
||||
current_user: Annotated[dict, Security(get_current_user, oauth_scopes=["me"])],
|
||||
):
|
||||
call_counts["get_user_me"] += 1
|
||||
return {
|
||||
|
|
@ -59,7 +59,7 @@ def app_fixture(call_counts: dict[str, int]):
|
|||
@app.get("/")
|
||||
def path_operation(
|
||||
user_me: Annotated[dict, Depends(get_user_me)],
|
||||
user_items: Annotated[dict, Security(get_user_items, scopes=["items"])],
|
||||
user_items: Annotated[dict, Security(get_user_items, oauth_scopes=["items"])],
|
||||
):
|
||||
return {
|
||||
"user_me": user_me,
|
||||
|
|
|
|||
Loading…
Reference in New Issue