New Features
Dependency based permission checking
This release introduces a new way of handling authorisation. The library now favours a dependency based approach for permission handling instead of the previous decorator based approach.
Warning
The old decorator based approach using the @require_permission
decorator is now deprecated and will be removed in version 2 of this library. For now, no breaking changes have been introduced. See the section about deprecations below for details
Migration
The most simple case is a normal permission. In this case, it can simply be rewritten by changing the @require_permission
decorator to the CheckPermission
dependency as follows:
# Old
@router.get("/your-endpoint")
@require_permission("your_permission")
async def your_endpoint(user = Depends(get_user)):
pass
# New
@router.get(
"/your-endpoint",
dependencies=[Depends(CheckPermissions("your_permission"))],
)
async def your_endpoint():
pass
Tip
Note that the new version doesn't include the get_user
dependency anymore. Using the CheckPermission
dependency automatically makes sure a user is successfully authenticated by presenting a valid token. You can of course still use the get_user
dependency is you need a reference to the user:
@router.get(
"/your-endpoint",
dependencies=[Depends(CheckPermissions("your_permission"))],
)
async def your_endpoint(user = Depends(get_user)):
pass
Complex permission matching
The new approach supports the same more complex patterns that the decorator based approach supported. You can provide a list of permissions and optionally a strategy that should be applied:
@router.get(
"/your-endpoint",
dependencies=[Depends(CheckPermissions(["your_first_permission", "your_second_permission"], match_strategy=MatchStrategy.OR))],
)
async def your_endpoint():
pass
Accessing the authorisation result
If you need to access the result (e.g. based on which permission the user was allowed access), you can now simply use the dependency result instead of using the decorator + the legacy get_authorization_result
dependency:
@router.get("/your-endpoint")
async def your_endpoint(authorization_result: AuthorizationResult = Depends(CheckPermissions(["your_first_permission", "your_second_permission"], match_strategy=MatchStrategy.OR))):
pass
New Doc section: testing
The docs have been extended and now include a section about my perceived best practices when testing applications secured by this library. These might not be the best ideas, I'm happy to hear about better options.
Deprecations
require_permission
decorator is deprecated and scheduled to be removed in the next major release.
The previous approach was based on the middleware injecting users and roles into the request scope, and then having the require_permission
extracting them from the request to perform access validation. It then injects the authorisation result to the next function call, but only if the dependency has been added to the method.
This approach was quite inflexible and "hacky", it required manual modification of the method signature if the dependency was used. This new approach makes testing simpler, will allow us to remove fairly complicated code in the future and is more in line with FastAPI principles.
get_authorization_result
is being marked as deprecated and is scheduled to be removed in the next major release.
Important
Both methods will emit a standard Python DeprecationWarning from this release onwards.
Full Changelog
feat: implement new way of handling authorization, switching away from the decorator approach. Currently, the decorator approach is still supported, it is marked deprecated in this release though.
[docs: adjust docs to correctly have authorization related config settings in KeycloakConfiguration. Fixes https://github.com//issues/54
build: raise version number to 1.0.2
fix: deprecation warnings after switching to Pydantic v2
fix: type hint of validation_option had wrong brackets](docs: adjust docs to correctly have authorization related config settings in KeycloakConfiguration. Fixes #54)docs: adjust docs to correctly have authorization related config settings in KeycloakConfiguration. Fixes #54
fix: remove non-required statements from init file
dev: add mypy cache files to gitignore
style: fix various typing issues
Full Changelog: v1.0.2...v1.1.0