معرفی شرکت ها


drf-remotejwt-0.1.2


Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر
Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر
Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر
Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر
Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر

توضیحات

A package to authenticate against a remote Authentication Service that support JWTs, think microservice authentication backend.
ویژگی مقدار
سیستم عامل -
نام فایل drf-remotejwt-0.1.2
نام drf-remotejwt
نسخه کتابخانه 0.1.2
نگهدارنده []
ایمیل نگهدارنده []
نویسنده Garreth Cain
ایمیل نویسنده garrethccain@gmail.com
آدرس صفحه اصلی https://github.com/garrethcain/drf-remotejwt
آدرس اینترنتی https://pypi.org/project/drf-remotejwt/
مجوز AGPL-3
# DRF-RemoteJWT This is a package for the implementation of a remote authentication backend for Django apps, primarily meant for use with JWTs but supporting sessions as well. Ie. elevated users could log into the Django `/admin/` once authenticated. The target is of course microservice ecosystems, with several APIs. The PyPi package can be found here: https://pypi.org/project/drf-remotejwt/ This package is used in the example [auth-client-service-example](https://github.com/garrethcain/auth-client-service-example) project. There are, at a minimum, two components required for this to work; 1. An Auth-Service with SimpleJWT, to authenticate against, 2. A Client-Service, with this package, users want to use. The idea being that you can have any number of client-services using the auth-service to validate login requests and your auth-service is behind some kind of private network. Ie. not public facing. This package is a wrapper for all the main components of the auth-service; eg. * /token/ to obtain an access and a refresh token, and create/update the local instance. * /token/refresh/ to refresh an expired access token. * /token/verify/ to confirm if a token is valid or not. The above urls in the client-service just proxy requests to the remote the Auth-Service, configured in `settings.py` `REMOTE_JWT` dict, but creating a local user object if required. All that is needed is to add the DRF-RemoteJWT URLs to your client-service. The auth-service remains mostly vanilla asside from maybe using a custom User model, include in this package as well, for convenience. You can't create users in the local client-service! If you retrieve a user from the auth-service with the same ID you will overwrite the local record with data from the auth-service. Your project can use HMAC by implementing some HMAC backend locally. The HMAC keys will be kept local to the service and not centralised in the Auth-Service. The Auth-Service is intentionally kept lean and only handles "users". # Get Started What we'll be doing; 1. Create an Auth-Service 2. Create a Client-Service ## Create an Auth-Service Always upgrade pip first. ``` $ pip install --upgrade pip ``` Create a temporary virtual environment to install django so we can create a project. ``` $ python -m virtualenv .venv ``` Activate the virtual environment. ``` $ source .venv/bin/activate ``` Your terminal should look something like this; `(.venv) user@domain  ~/Code/ ` With the `(.venv)` part implying you're currently inside a virtual environment. Install Django so we can create our app. ``` $ pip install django ``` Create our project with the name `config` so the nested directory is named more conveniently. ```PYTHON $ django-admin startproject config ``` Rename the outer directory because I personally like having the project's config kept in a directory called `config` with the outer directory the name of project. ```PYTHON $ mv config auth-service ``` You should have a directory structure similar to this. ``` ─── auth-service ├── config │   ├── __init__.py │   ├── asgi.py │   ├── settings.py │   ├── urls.py │   └── wsgi.py └── manage.py ``` Now let's remove the temp virtual environment by deactivating, deleting the old one, then creating a new on in the right place. ``` $ deactivate ``` Your terminal should be back to something like this; `user@domain  ~/Code/ ` Delete the files. ``` $ rm -Rf .venv ``` ``` $ cd auth-service ``` Create another virtual environment. ``` $ python -m virtualenv .venv ``` Activate the virtual environment, again. We'll keep this one this time. ``` $ source .venv/bin/activate ``` Again, your terminal should look something like this; `(.venv) user@domain  ~/Code/auth-service/ ` Install the packages we're going to use. ``` $ pip install django django_rest_framework djangorestframework-simplejwt drf-remotejwt ``` Open `config/settings.py` and add the apps we'll be using to `INSTALLED_APPS`; ```PY INSTALLED_APPS = [ ... 'rest_framework', 'rest_framework_simplejwt', 'remotejwt_user', ] ``` We've included `remotejwt_user` so we can use the same User model between all services. It also includes some convieniences such as update forms and changes the Username field from `username` to `email`. Tell Django about the new user model by adding; ```py AUTH_USER_MODEL = "remotejwt_user.User" ``` Next we need to configure Django Rest Framework. For this example you need just the following; ```PYTHON REST_FRAMEWORK = { "DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",), "DEFAULT_AUTHENTICATION_CLASSES": ( "rest_framework.authentication.SessionAuthentication", "rest_framework_simplejwt.authentication.JWTAuthentication", ), } ``` In order to use Rest Framework SimpleJWT you will also need to add some configuration for it. ```PY SIMPLE_JWT = { "ACCESS_TOKEN_LIFETIME": timedelta(minutes=5), "REFRESH_TOKEN_LIFETIME": timedelta(days=1), "ROTATE_REFRESH_TOKENS": False, "BLACKLIST_AFTER_ROTATION": False, "UPDATE_LAST_LOGIN": False, "ALGORITHM": "HS256", "SIGNING_KEY": "d577273ff885c3f84dadb8578bb40000", # You must set the correctly for Production. "VERIFYING_KEY": None, "AUDIENCE": None, "ISSUER": None, "JWK_URL": None, "LEEWAY": 0, "USER_ID_FIELD": "id", "USER_ID_CLAIM": "user_id", "USER_AUTHENTICATION_RULE": "rest_framework_simplejwt.authentication.default_user_authentication_rule", "AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",), "TOKEN_TYPE_CLAIM": "token_type", "TOKEN_USER_CLASS": "rest_framework_simplejwt.models.TokenUser", "JTI_CLAIM": "jti", "SLIDING_TOKEN_REFRESH_EXP_CLAIM": "refresh_exp", "SLIDING_TOKEN_LIFETIME": timedelta(minutes=5), "SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=1), } ``` In the JWT configuration we use `timedelta` so you need to import `timedelta` at the top of `config/settings.py`. `from datetime import timedelta` Make migrations so we can migrate. ``` $ python manage.py makemigrations ``` Migrate to create the database. An SQLite db is fine for the example. In a production environment you'd use something a bit more appropriate. ``` $ python manage.py migrate ``` And finally you can stand up the auth-service with; ``` $ python manage.py runserver ``` Which should get you something like; ``` Watching for file changes with StatReloader Performing system checks... System check identified no issues (0 silenced). May 02, 2023 - 10:50:48 Django version 4.0.2, using settings 'config.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C. ``` Hit `^C` so we can create a few users for testing with later on. We're going to create three test users as below. * admin | admin@test.com | admin-pass * staff | staff@test.com | staff-pass * user | user@test.com | user-pass Eg. ``` export DJANGO_SUPERUSER_EMAIL=admin@test.com export DJANGO_SUPERUSER_USERNAME=admin export DJANGO_SUPERUSER_PASSWORD=admin-pass python manage.py createsuperuser --noinput ``` or ``` $ python manage.py createsuperuser ``` Then stand up the auth-service and log into `http://127.0.0.1:8000/admin/` login with the superuser you created above and create the other two users, setting `is_staff=True` for the staff user. Log out once you're done and terminate the instance that's running with `^C` and deactivate this virtual environment. ``` $ deactivate ``` The final step is to configure the Urls. So open `config/urls.py` and add the following. Import the SimpleJWT views; ```py from rest_framework_simplejwt.views import ( TokenObtainPairView, TokenRefreshView, TokenVerifyView, ) ``` Then expost the paths to the JWT endpoints and a user view which is where the client-service will download the user from. ```py urlpatterns = [ ... path("auth/token/", TokenObtainPairView.as_view(), name="token_obtain_pair"), path("auth/token/refresh/", TokenRefreshView.as_view(), name="token_refresh"), path("auth/token/verify/", TokenVerifyView.as_view(), name="token_verify"), path('auth/', include('remotejwt_user.urls')), ] ``` And that's it for the Auth-Service. It doesn't need any views or serializers. Everything is handled by SimpleJWT and Django's OEM methods. This service is super light to run and will handle all requests with easy. --- ## Create a Client-Service Now we need a client-service that will authenticate against the Auth-Service to complete the example. Go up one directory; ``` cd .. ``` We're going to perform the same steps for the client-service that we did for the auth-service. You should recognise most of this. The main difference is that this time we'll be using `drf-remotejwt` and not creating any local users. Create a temporary virtual environment to install django so we can create a project. ``` $ python -m virtualenv .venv ``` Activate the virtual environment. ``` $ source .venv/bin/activate ``` Your terminal should look something like this; `(.venv) user@domain  ~/Code/ ` With the `(.venv)` part implying you're currently inside a virtual environment. Install Django so we can create our app. ``` $ pip install django ``` Create our project with the name `config` so the nested directory is named more conveniently. ```PYTHON $ django-admin startproject config ``` Rename the outer directory because I personally like having the project's config kept in a directory called `config` with the outer directory the name of project. ```PYTHON $ mv config client-service ``` You should have a directory structure similar to this. ``` ├── auth-service │   ├── config │   │   ├── __init__.py │   │   ├── asgi.py │   │   ├── settings.py │   │   ├── urls.py │   │   └── wsgi.py │   ├── db.sqlite3 │   └── manage.py └── client-service ├── config │   ├── __init__.py │   ├── asgi.py │   ├── settings.py │   ├── urls.py │   └── wsgi.py └── manage.py ``` Now let's remove the temp virtual environment by deactivating, deleting the old one, then creating a new on in the right place. ``` $ deactivate ``` Your terminal should be back to something like this; `user@domain  ~/Code/ ` Delete the files. ``` $ rm -Rf .venv ``` ``` $ cd client-service ``` Create another virtual environment. ``` $ python -m virtualenv .venv ``` Activate the virtual environment, again. We'll keep this one this time. ``` $ source .venv/bin/activate ``` Again, your terminal should look something like this; `(.venv) user@domain  ~/Code/auth-service/ ` Install the packages we're going to use. We don't need `SimpleJWT` this time because authentication is handled by the remote auth-service. ``` $ pip install django django_rest_framework drf-remotejwt ``` We need to let Django know about the apps we'll be using, so open `settings.py` and add the following lines to `INSTALLED_APPS`; ```PY INSTALLED_APPS = [ ... 'rest_framework', 'remotejwt', 'remotejwt_user', ] ``` We need to use the same User model as the auth-service, otherwise the user returned by the auth-service will cause an integrity error. ```py AUTH_USER_MODEL = "remotejwt_user.User" ``` Add some configuration for Djang Rest Framework. Change the default behaviour for all endpoints to require authentication. Then we override the default authentication classes with the ones from `DRF-RemoteJWT`. ```py REST_FRAMEWORK = { "DEFAULT_PERMISSION_CLASSES": ( "rest_framework.permissions.IsAuthenticated", ), "DEFAULT_AUTHENTICATION_CLASSES": ( "remotejwt.authentication.RemoteJWTAuthentication", # Use our service "rest_framework.authentication.SessionAuthentication", # Maybe the user has a session... ), } ``` Let Django know that we want to use a custom authentication backend. ```py # implement out or custom backend for Admin and other views. AUTHENTICATION_BACKENDS = [ 'django.contrib.auth.backends.ModelBackend', # Default, check the local DB. 'remotejwt.authentication.ModelBackend' # Our override to check the remote service. ] ``` Time to configure `DRF-RemoteJWT`. For this example example we're going to run the auth-server on `:8000` and the client-service on `:8001`. Most of this conf should be handled through environmental variables in a real project. But we're just aiming for the absolute minimal working example. ```py REMOTE_JWT = { "AUTH_HEADER_TYPE": "Bearer", "AUTH_HEADER_NAME": "Authorization", "REMOTE_AUTH_SERVICE_URL": "http://127.0.0.1:8000", # Where do we reach the Auth-Service "REMOTE_AUTH_SERVICE_TOKEN_PATH": "/auth/token/", # The path to login and retrieve a token "REMOTE_AUTH_SERVICE_REFRESH_PATH": "/auth/token/refresh/", # The path to refresh a token "REMOTE_AUTH_SERVICE_VERIFY_PATH": "/auth/token/verify/", # The path to verify a token "REMOTE_AUTH_SERVICE_USER_PATH": "/auth/users/{user_id}/", # The path to get the user object "USER_ID_FIELD": "id", "USER_ID_CLAIM": "user_id", } ``` Open `config/urls.py` and add the URLs from RemoteJWT that will be passed through to the auth-service. ```py from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('auth/', include("remotejwt.urls")) ] ``` Don't forget the `include` import. We'll add our test view to the urls as well shortly. All the client-service needs now is an endpoint to prove it's alive. So let's add a Django app with a view that requires authentication we use to test. ```py $ django-admin startapp test_app ``` Your directory structure should now look something along the lines of; ``` . ├── config │   ├── __init__.py │   ├── asgi.py │   ├── settings.py │   ├── urls.py │   └── wsgi.py ├── manage.py └── test_app ├── __init__.py ├── admin.py ├── apps.py ├── migrations │   └── __init__.py ├── models.py ├── tests.py └── views.py ``` You can see the new app called `test_app` has been added. Open `test_app/views.py` and add the following view. Because we changed the Rest Framework config to use a `DEFAULT_PERMISSION_CLASSES` of `IsAuthenticated` all views will require authentication. ```py from rest_framework import generics from rest_framework.response import Response class TestView(generics.GenericAPIView): def get(self, request): return Response("success", status=200) ``` There are no models or serializers, it's the absolute least we can do to get a success. There is no need to add the `test_app` to the `INSTALLED_APPS` because it has no models that need migrating. The absolute final step before we can run some tests is to add the `TestView` to the client-service's Urls.py so it knows where to send an incoming request. ```py from django.urls import path, include from test_app.views import TestView urlpatterns = [ path('admin/', admin.site.urls), path('auth/', include("remotejwt.urls")), path('api/test/', TestView.as_view()), ] ``` Don't forget it include the `include` import at the end of `from django.urls import path` at the top of the `urls.py` file. Modfiy the `config/urls.py` so it looks like the above. First we import the `TestView` from `test_app` and then we give it a path, in this case `/api/test/`. Let's migrate the client-service so it has a database to write the user to. ``` $ python manage.py makemigrations ``` ``` $ python manage.py migrate ``` ## Standing up the Services As mentioned earlier, we have two services and auth-service and a client-service . We want the auth-service to be on `:8000` and the client-service to be at `:8001`. **This is important because it's how we configure the RemoteJWT's configuration in the client-service.** You'll need two terminals. One in auth-service/ and one in client-service/ both with the respective virtual environments loaded and then a third one to execute the requests from using `curl`. In auth-service, stand up on port `:8000` like; ``` (.venv) user@domain > ~/Code/auth-service $ python manage.py runserver 0.0.0.0:8000 ``` And then stand up the client-service on port `:8001` like this; ``` (.venv) user@domain > ~/Code/client-service $ python manage.py runserver 0.0.0.0:8001 ``` --- # How to test the API In the below examples we're mking requests to super simple API (client-service) which will reach out to the auth-service to retrieve, verify, and if needed refresh the tokens. You can check the client-service's db.sqlite3 database before making any requests to confirm the `user` table is empty. After making a few successful requests there will be some users there. Remember the users added to the auth-service further back? You'll need those email and passwords shortly. Also remember that the auth-service is at `:8000` and the client-service is at `:8001`. As a client-service user, we should never interact with the auth-service directly. It shouldn't even be accessible to the public in a normal production environment. ## Authorise and obtain a token pair `curl \ -X POST \ -H "Content-Type: application/json" \ -d '{"email": "user@test.com", "password": "user-pass"}' \ http://127.0.0.1:8001/auth/token/` Will give you a response like; ```JSON { "refresh":" ... ", "access":" ... " } ``` (I removed the tokens above for brevity.) ## Perform a generic API requst Export the access token from the previous response to an envar. eg. `export ACCESS_TOKEN={paste_token_here}` Should return 'success'. `curl \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ http://127.0.0.1:8001/api/test/` The response should be; ```JSON "success" ``` ## Refresh an expired token `curl \ -X POST \ -H "Content-Type: application/json" \ -d '{"refresh": "${REFRESH_TOKEN"}}' \ http://127.0.0.1:8001/auth/token/refresh/` ## Verify the token is correct Performed by the client-service against the auth-service with every single JWT API request. `curl \ -X POST \ -H "Content-Type: application/json" \ -d '{"token": "${REFRESH_TOKEN}"}' \ http://127.0.0.1:8001/auth/token/verify/` ## Get the user details This would be done inside the Auth handler when the user doesn't exist. There needs to be a valid user_id for the user associated with the access token being used. Ie. you can't view other user objectss by guessing an ID. Only your own. `curl \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ http://localhost:8001/auth/users/{user_id}/`


نیازمندی

مقدار نام
>=3.2 Django
>=3.12.4 djangorestframework
>=2.24.0 requests


زبان مورد نیاز

مقدار نام
>=3.6 Python


نحوه نصب


نصب پکیج whl drf-remotejwt-0.1.2:

    pip install drf-remotejwt-0.1.2.whl


نصب پکیج tar.gz drf-remotejwt-0.1.2:

    pip install drf-remotejwt-0.1.2.tar.gz