generated from rayluo/python-project-template
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'step-up-consent' into dev
- Loading branch information
Showing
9 changed files
with
478 additions
and
337 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
.. tip:: | ||
|
||
We recommend | ||
`storing settings in environment variables. <https://12factor.net/config>`_. | ||
The snippet above read data from environment variables. | ||
|
||
.. | ||
This is a comment. | ||
The table below was built via https://tableconvert.com/restructuredtext-generator | ||
.. admonition:: Initializing Auth object differently based on Identity Provider type | ||
|
||
+------------------------------------------------+-----------------------------------------------------------+--------------------------------------------------------------------------+ | ||
| | Its authority URL looks like | Initialize Auth() object like this | | ||
+================================================+===========================================================+==========================================================================+ | ||
| Microsoft Entra ID | ``https://login.microsoftonline.com/tenant`` | Auth(..., authority=url, ...) | | ||
+------------------------------------------------+-----------------------------------------------------------+ + | ||
| Microsoft Entra External ID | ``https://contoso.ciamlogin.com/contoso.onmicrosoft.com`` | | | ||
+------------------------------------------------+-----------------------------------------------------------+--------------------------------------------------------------------------+ | ||
| Microsoft Entra External ID with Custom Domain | ``https://contoso.com/tenant`` | Auth(..., oidc_authority=url, ...) | | ||
+------------------------------------------------+-----------------------------------------------------------+--------------------------------------------------------------------------+ | ||
| Azure AD B2C | N/A | Auth(..., b2c_tenant_name="contoso", b2c_signup_signin_user_flow="susi") | | ||
+------------------------------------------------+-----------------------------------------------------------+--------------------------------------------------------------------------+ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
Identity for Django | ||
=================== | ||
|
||
Prerequisite | ||
------------ | ||
|
||
Create a hello world web project in Django. | ||
|
||
You can use | ||
`Django's own tutorial, part 1 <https://docs.djangoproject.com/en/5.0/intro/tutorial01/>`_ | ||
as a reference. What we need are basically these steps: | ||
|
||
1. ``django-admin startproject mysite`` | ||
2. ``python manage.py migrate`` | ||
3. ``python manage.py runserver localhost:5000`` | ||
You must use a port matching your redirect_uri that you registered. | ||
|
||
4. Now, add an `index` view to your project. | ||
For now, it can simply return a "hello world" page to any visitor:: | ||
|
||
from django.http import HttpResponse | ||
def index(request): | ||
return HttpResponse("Hello, world. Everyone can read this line.") | ||
|
||
Django configuration | ||
-------------------- | ||
|
||
1. Firstly, create an instance of the :py:class:`identity.django.Auth` object, | ||
and assign it to a global variable inside your ``settings.py``:: | ||
|
||
import os | ||
from dotenv import load_dotenv | ||
from identity.django import Auth | ||
load_dotenv() | ||
AUTH = Auth( | ||
os.getenv('CLIENT_ID'), | ||
client_credential=os.getenv('CLIENT_SECRET'), | ||
redirect_uri=os.getenv('REDIRECT_URI'), | ||
..., # See below on how to feed in the authority url parameter | ||
) | ||
|
||
.. include:: auth.rst | ||
|
||
2. Inside the same ``settings.py`` file, | ||
add ``"identity"`` into the ``INSTALLED_APPS`` list, | ||
to enable the default templates came with the identity package:: | ||
|
||
INSTALLED_APPS = [ | ||
..., | ||
"identity", | ||
] | ||
|
||
3. Add the built-in views into your ``urls.py``:: | ||
|
||
from django.conf import settings | ||
|
||
urlpatterns = [ | ||
settings.AUTH.urlpattern, | ||
... | ||
] | ||
|
||
Django Web App Sign In | ||
---------------------- | ||
|
||
4. In your web project's ``views.py``, decorate some views with the | ||
:py:func:`identity.django.Auth.login_required` decorator:: | ||
|
||
from django.conf import settings | ||
|
||
@settings.AUTH.login_required | ||
def index(request, *, context): | ||
user = context['user'] | ||
return HttpResponse(f"Hello, {user.get('name')}.") | ||
|
||
Web app that logs in users and calls a web API on their behalf | ||
-------------------------------------------------------------- | ||
|
||
5. Decorate your token-consuming views using the same | ||
:py:func:`identity.django.Auth.login_required` decorator, | ||
this time with a parameter ``scopes=["your_scope_1", "your_scope_2"]``. | ||
|
||
Then, inside your view, the token will be readily available via | ||
``context['access_token']``. For example:: | ||
|
||
@settings.AUTH.login_required(scopes=["your_scope"]) | ||
def call_api(request, *, context): | ||
api_result = requests.get( # Use access token to call a web api | ||
"https://your_api.example.com", | ||
headers={'Authorization': 'Bearer ' + context['access_token']}, | ||
timeout=30, | ||
).json() # Here we assume the response format is json | ||
... | ||
|
||
All of the content above are demonstrated in | ||
`this django web app sample <https://github.com/Azure-Samples/ms-identity-python-webapp-django>`_. | ||
|
||
|
||
API for Django web projects | ||
--------------------------- | ||
|
||
.. autoclass:: identity.django.Auth | ||
:members: | ||
:inherited-members: | ||
|
||
.. automethod:: __init__ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
Low-level API for generic web projects | ||
====================================== | ||
|
||
Web app that logs in users | ||
-------------------------- | ||
|
||
1. Firstly, create an instance of the :py:class:`identity.web.Auth` object, | ||
and assign it to a (typically global) variable:: | ||
|
||
auth = identity.web.Auth( | ||
session=session, # A session object is a key-value storage with a | ||
# dict-like interface. Many web frameworks provide this. | ||
authority="https://login.microsoftonline.com/common", | ||
client_id="your_app_client_id", | ||
client_credential="your_secret", | ||
) | ||
|
||
2. Now, in your web app's login controller, call the | ||
``auth.log_in(scopes=["your_scope"], redirect_uri="https://your_app.example.com/redirect_uri")`` | ||
(see also :py:meth:`.log_in`) | ||
to obtain the ``auth_uri`` (and possibly a ``user_code``), | ||
and then render them into your login html page. | ||
|
||
3. The second leg of log-in needs to be implemented in another controller, | ||
which calls ``auth.complete_log_in(incoming_query_parameters)`` | ||
(see also :py:meth:`.complete_log_in`). | ||
If its returned dict contains an ``error``, then render the error to end user, | ||
otherwise your end user has successfully logged in, | ||
and his/her information is available as a dict returned by | ||
:meth:`identity.web.Auth.get_user`. | ||
In particular, the returned dict contains a key named ``sub``, | ||
whose value is the unique identifier which you can use to represent this end user | ||
in your app's local database. | ||
|
||
4. Don't forget to add one more controller for log out. You do it by calling | ||
``auth.log_out("https://your_app.example.com")``. | ||
Please refer to :meth:`.log_out`'s docs for more details about its return value. | ||
|
||
All of the content above are demonstrated in this sample (link to be provided). | ||
|
||
|
||
Web app that logs in users and calls a web API on their behalf | ||
-------------------------------------------------------------- | ||
|
||
Building on top of the previous scenario, you just need to call | ||
``auth.get_token_for_user(["your_scope"])`` to obtain a token object. | ||
See :py:meth:`identity.web.Auth.get_token_for_user` for more details. | ||
And you can see it in action in this sample (link to be provided). | ||
|
||
|
||
Generic API, currently used for Flask web apps | ||
---------------------------------------------- | ||
|
||
.. autoclass:: identity.web.Auth | ||
:members: | ||
:inherited-members: | ||
|
||
.. automethod:: __init__ | ||
|
Oops, something went wrong.