{"id":17618152,"url":"https://github.com/yorek/dps-2020","last_synced_at":"2025-03-30T00:42:53.686Z","repository":{"id":73841639,"uuid":"311748315","full_name":"yorek/dps-2020","owner":"yorek","description":"Demos used at the Data Platform Summit 2020","archived":false,"fork":false,"pushed_at":"2020-12-03T02:23:30.000Z","size":25,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-02-05T02:49:03.582Z","etag":null,"topics":["api","azure-sql","azure-sql-db","conferences","rest","security"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yorek.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-11-10T18:22:30.000Z","updated_at":"2020-12-03T02:23:32.000Z","dependencies_parsed_at":"2023-07-21T17:02:07.412Z","dependency_job_id":null,"html_url":"https://github.com/yorek/dps-2020","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yorek%2Fdps-2020","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yorek%2Fdps-2020/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yorek%2Fdps-2020/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yorek%2Fdps-2020/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yorek","download_url":"https://codeload.github.com/yorek/dps-2020/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246262491,"owners_count":20749171,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","azure-sql","azure-sql-db","conferences","rest","security"],"created_at":"2024-10-22T19:26:32.277Z","updated_at":"2025-03-30T00:42:53.667Z","avatar_url":"https://github.com/yorek.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Data Platform Summit 2020 Demos\n\n![License](https://img.shields.io/badge/license-MIT-green.svg)\n\nDemo used in the \"Data Platform Summit 2020\" for the session \n\n**Create secure API with .NET, Dapper and Azure SQL**\n\n## Pre-requisites\n\nMake sure you have an Azure SQL database to use for this demo. If you need help to create an Azure SQL database, take a look here: [Running the samples](https://github.com/yorek/azure-sql-db-samples#running-the-samples)\n\nYou will also need Visual Studio Code or Visual Studio 2019 and .NET Core SDK 3.1 \n\n## Iteration 1 - Create ToDo Backend API\n\nIn this first step, you will create a fully functioning [backend REST API](http://www.todobackend.com/) for the [ToDo MVC](http://todomvc.com/) Project. The REST API to be created are defined via a series of automated test as described here:\n\n[Creating a new Todo-Backend API implementation](http://www.todobackend.com/contribute.html)\n\nthe test can be download and executed locally using a local server, like [Visual Studio Code Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer):\n\n[Executable Specs in JavaScript for the Todo-Backend API](https://github.com/TodoBackend/todo-backend-js-spec)\n\nTo run the backend API locally, configure the `appsettings.json` to include connection string to the Azure SQL database you want to use for the demo:\n\n```json\n\"ConnectionStrings\": {\n    \"AzureSQL\": \"SERVER=\u003cmyserver\u003e.database.windows.net;DATABASE=\u003cmydatabase\u003e;UID=todo-backend;PWD=Super_Str0ng*P@ZZword!;\"\n}\n```\n\nmake also sure to have created all the needed objects and user, by executing the script `./Database/01-create-objects.sql` in your Azure SQL database. Then, you can just run\n\n```\ndotnet run\n```\n\nto start the backend and test it using the aforementioned test or a REST tool like [Insomnia](https://insomnia.rest/) to send HTTP requests. For example you can create a new Todo by sending a POST request with \n\n```json\n{\n\t\"title\": \"my todo\"\n}\n```\n\nas body to `http://localhost:5000/todo` endpoint.\n\nIf you try to run the ToDo Backend REST Endpoint test (for example: `http://localhost:5500/index.html?http://localhost:5000/todo`) all tests should be greem with the exception of the test under \"tracking todo order\" section.\n\n## Iteration 2 - Add support to a new property\n\nWe now want to support also the ability to set an order or priority for the ToDo we have. We just have to add a new column to the table and update the related stored procedures. As we didn't use a POCO object and just relied on JSON, there will be no changes needed on the .NET code.\n\nSimply run the `./Database/02-add-order.sql` script in the Azure SQL database used for the sample.\n\nNow re-run the test. Every test should be passing now.\n\nCongratulations, you just extended your schema so that it can now store the `order` field.\n\nIF you want to see other options to manage schema dynamically, maybe that doesn't even require altering the table and updating the stored procedures, take a look here:\n\n[Cloud Day 2020 Demos - Serverless Scalable Back-End API with Hybrid Data Models](https://github.com/yorek/cloud-day-2020)\n\n## Iteration 3 - Add security\n\nIt's now time to add security to make sure only authorized user will be able to access to Todo items. First of all you need to setup and enable [Row-Level Security](https://docs.microsoft.com/en-us/sql/relational-databases/security/row-level-security), via the `./Database/enable-rls.sql` script. \n\nAfter the script has been executed, RLS will be configured but still in *disabled* state.\n\nLet's now execute the `./Database/04-test-rls.sql` up to the [line 26](https://github.com/yorek/dps-2020/blob/main/Database/04-test-rls.sql#L26) so that RLS will be enabled thanks to the\n\n```sql\nalter security policy rls.todo_access_policy\nwith (state = on);  \n```\n\nstatement. The script will also wipe clean all the todo, and create just a couple of sample todo, useful for testing RLS. \n \nIf you try now to get all todos via the GET HTTP request, you'll get an empty array. You don't have yet any authorization to see anything, so RLS is preventing you to access any existing Todo.\n\n### Creating a JTW token\n\nYou need to pass the REST Endpoint a JWT token with details on who you are. The sample contains a `authorization` endpoint that simulates an endpoint that will authenticate the user and will return a valid JWT token, containing the User Hash Id that can be used to allow the authenticated user to access a specific Todo.\n\nIn order to simulate authentication, you can POST a Login and Password, for example:\n\n```json\n{\n    \"login\": \"john.doe@contoso.com\",\n    \"password\": \"anything-here\"\n}\n```\n\nto http://localhost:5000/authorization. You can pass any login or password, as the sample authorization will always return a JWT token containing the User Hash ID \"12345\". You can see the content of the JWT token via [jwt.io](https://jwt.io/)\n\nYou now have to update the REST API sample so that it will be able to use that token. Make sure you uncomment the [line 74](https://github.com/yorek/dps-2020/blob/main/Startup.cs#L74) in `Startup.cs`:\n\n```csharp\napp.UseAuthentication();\n```\n\nto allow a user to be authenticated and thus then authorized, and also uncomment the `Authorize` attribute at [line 32](https://github.com/yorek/dps-2020/blob/main/Controllers/ToDoController.cs#L32) of `./Controllers/ToDoController.cs` and [line 52](https://github.com/yorek/dps-2020/blob/main/Controllers/ToDoController.cs#L52) in the same file to pass to Azure SQL database the Session Context with the User Hash Id available in the JWT token:\n\n```csharp\nawait conn.ExecuteAsync(\"sys.sp_set_session_context\", new { @key = \"user-hash-id\", @value = userHashId, @read_only = 1 }, commandType: CommandType.StoredProcedure );\n```\n\nYou now have to allow user with Hash Id 12345 to be able to access a Todo. For example, to allow access to ToDo 1:\n\n```sql\ninsert into rls.[todo_permissions] \n    (user_hash_id, todo_id, can_access)\nvalues \n    (12345, 1, 1)\n```\n\nYou can now run the backend API again and if you try to GET the list of todo, only the authorized todo will be available. Make sure to authenticated your REST calls by [passing the generated JWT token](https://support.insomnia.rest/article/38-authentication) as the [Bearer Token](https://stackoverflow.com/questions/25838183/what-is-the-oauth-2-0-bearer-token-exactly).\n\n## Conclusion\n\nDone, your GET endpoint is now secured.\n\nI'll leave it to you to move forward and secure all the other endpoint for POST, DELETE and PATCH, as the approach is very similar to what has been done already for the GET one.\n\nHave fun!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyorek%2Fdps-2020","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyorek%2Fdps-2020","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyorek%2Fdps-2020/lists"}