- An example of Python3 FastAPI, Keycloak and MongoDB.
- Keycloak takes care of accounts, access, permissions, privileges and session management, letting the application code very light and yet secured.
- And yes, MongoDB supports atomic operations -- letting the logic to "check and debit (and also audit)" to work as one operation -- ensuring data integrity.
- The plan is to relinquish authentication from code and give it to standard IAM tools like keycloak.
- User account management, Profile management, Roles, Group, Permissions etc all are moved to keycloak.
- The plan is also to demonstrate Python3 FastAPI integration with keycloak and MongoDB.
- In this example, we are trying to show a Banking application.
- Allow Banks to create accounts (user accounts)
- Allow Users to add fund and withdraw (debit, credit)
- In this example, we have two types of Role:
- Role = bank_teller:
- for every bank there will be a user like (icici_teller) belonging to this role.
- This role/user will be able to create account(users account) for new customer.
- This role/user can see deposits in account.
- But, will not be able to add or withdraw from account.
- Role = account_owner:
- This is a general bank account user role. Example bob and charlie
- This role/user will be able to add and/or withdraw from his/her account.
- This role/user will be able to see fund balance in his/her account.
- Role = bank_teller:
- We also have two Groups:
- Group = hdfc:
- User list: charlie, hdfc_teller
- Group = icici:
- User list: bob, icici_teller
- Group = hdfc:
Present URL | Method | Description | Allowed by Roles | Users having this permission |
---|---|---|---|---|
/bank_user/{bank} | GET | to see balance | account_owner | bob, charlie |
/bank_user/{bank} | PUT | to transact (credit or debit) | account_owner | bob, charlie |
/bank_teller/{bank}/{user} | PUT | to create account for user in bank | bank_teller | icici_teller, hdfc_teller |
/bank_teller/{bank}/{user} | GET | to get balance for every account | bank_teller | icici_teller, hdfc_teller |
- You need python3 version 3.10+.
- And, you need to install necessary libraries by using command
python3 -m pip install -r requirements.txt
]$ cd docker/
]$ mkdir keycloak_data
]$ mkdir mongodb_data
]$ sudo docker login
]$ sudo docker compose -f docker_compose_keycloak_mongodb.yml --env-file docker_compose_env up
- MongoDB web -- http://localhost:8084
- Keycloak -- http://localhost:8085
- Application -- http://localhost:8086
- You will see database named=small_banks is auto created
- You will see collection named=banks.hdfc and banks.icici is also auto created
]$ sudo docker exec -it mongodb bash
root@mongodb:/# mongosh -u admin -p
Enter password: <get_password_from_file docker_compose_env>
test> show dbs
...
small_banks 24.00 KiB
test>
test> use small_banks
switched to db small_banks
small_banks> show collections
banks.hdfc
banks.icici
small_banks>
small_banks> db.banks.hdfc.find({})
small_banks> db.banks.icici.find({})
small_banks>
- go to keycloak http://127.0.0.1:8085/
- login with admin (password in file=docker/docker_compose_env)
- Select Keycloak drop down from top left -> Create realm -> Browser -> Select file docker/small_bank_init_keycloak.json -> Create
- After this you will see, below objects are auto created
- realm = small_bank
- client = sm:api
- user = bob (role=account_owner, group=icici) default password=password
- user = charlie (role=account_owner, group=hdfc) default password=password
- user = icici_teller (role=bank_teller , group=icici) default password=password
- user = hdfc_teller (role=bank_teller , group=hdfc) default password=password
]$ cd bin
]$ uvicorn main:app --log-level debug --port 8086 --host 127.0.0.1 --reload
- Before users can use their account, bank teller needs to create account for bob and charlie
- Go to http://127.0.0.1:8086/docs
- Authenticate as icici_teller
- Extend PUT /bank_teller/{bank}/{user}
- Try, giving bank=icici, user=bob
- Now logout, restart browser or clear session for icici_teller from keycloak admin page
- And, Authenticate as hdfc_teller
- Extend PUT /bank_teller/{bank}/{user}
- Try, giving bank=hdfc, user=charlie
- In keycloak, bob belongs to group=icici and charlie belongs to group=hdfc
- hence, we choose icici_teller to create bobs account
- and, hdfc_teller to create charlie account
- incase, icici_teller also creates account for charlie -- then charlie will have two accounts in both the banks
- But, to use icici account, charlie will need to be also added in keycloak group=icici
- GET /bank_user/{bank} # for bob use bank=icici, for charlie use bank=hdfc
- PUT /bank_user/{bank} # for bob use bank=icici, for charlie use bank=hdfc
curl -X 'PUT' \
'http://127.0.0.1:8086/bank_teller/icici/bob' \
-H 'accept: application/json' \
-H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJVNm0zNG1rNW1ZVFNpaUpWcE9QTFZERjZpdkhoU094TnAwQ096dXJhRGljIn0.eyJleHAiOjE3MjUwODU0OTksImlhdCI6MTcyNTA4NTE5OSwiYXV0aF90aW1lIjoxNzI1MDg1MTk5LCJqdGkiOiIzY2QxNjRjNy1kMWM4LTQ5ZGUtYTAzMi1hMjYzZWNlMzJlYWUiLCJpc3MiOiJodHRwOi8vMTI3LjAuMC4xOjgwODUvcmVhbG1zL3NtYWxsX2JhbmsiLCJhdWQiOlsic206YXBpIiwiYWNjb3VudCJdLCJzdWIiOiJhNmMyMzliMi1mOWI5LTQ3MzctOTc4NC1lYWNhOTRiYTRiYzYiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJzbTphcGkiLCJzaWQiOiI5NDI4NmZjNS1jOTQ2LTQwYjYtYTFlNC04YWUyYzBhZWY0YWIiLCJhY3IiOiIxIiwiYWxsb3dlZC1vcmlnaW5zIjpbImh0dHA6Ly8xMjcuMC4wLjE6ODA4NiJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiIsImRlZmF1bHQtcm9sZXMtc21hbGxfYmFuayJdfSwicmVzb3VyY2VfYWNjZXNzIjp7InNtOmFwaSI6eyJyb2xlcyI6WyJiYW5rX3RlbGxlciJdfSwiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJuYW1lIjoiSUNJQ0kgVGVsbGVyIiwiZ3JvdXBzIjpbIi9pY2ljaSJdLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJpY2ljaV90ZWxsZXIiLCJnaXZlbl9uYW1lIjoiSUNJQ0kiLCJmYW1pbHlfbmFtZSI6IlRlbGxlciIsImVtYWlsIjoidGVsbGVyQGljaWNpLmNvIn0.xi7elqZ2EyfZrqWjkYAJwpHiJJxdUp8hwwhkXdECclkwd7Ds5hjymw6GYS2cy-cNa7Jz9escPYVYV1MyCN5O673FmPiIsnL2CdW4Mqf4236_20Uam71GcZpzSjs4DiYAm8KtsI8ux13FoklF1ou8S9Lml0Xh_XIG2-wq4jNnxxUlrlQMxgRllgEPme7oxIE4oJJkiOmVW2WFQWYeANKa7vhJ7IOe_mmiqzTn39vdGEmijxzfkE5hInmJtzW0-w9D0dTp5ZObAitxbth5-qupCzvgXwRmV-LM1gGNpNbIp7uKr_QdXZqsthpyURBC_KixR9IxN4RGHVeFybDCKUDaYA'