├── .gitignore ├── LICENSE ├── Projects ├── JwtDemo │ ├── Controllers │ │ ├── ApiController.cs │ │ ├── HomeController.cs │ │ └── PbApiController.cs │ ├── JwtDemo.csproj │ ├── Models │ │ └── ErrorViewModel.cs │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Views │ │ ├── Home │ │ │ ├── Index.cshtml │ │ │ └── Privacy.cshtml │ │ ├── Shared │ │ │ ├── Error.cshtml │ │ │ ├── _Layout.cshtml │ │ │ ├── _Layout.cshtml.css │ │ │ └── _ValidationScriptsPartial.cshtml │ │ ├── _ViewImports.cshtml │ │ └── _ViewStart.cshtml │ ├── appsettings.Development.json │ ├── appsettings.json │ └── wwwroot │ │ ├── css │ │ └── site.css │ │ ├── favicon.ico │ │ ├── js │ │ └── site.js │ │ └── lib │ │ ├── bootstrap │ │ ├── LICENSE │ │ └── dist │ │ │ ├── css │ │ │ ├── bootstrap-grid.css │ │ │ ├── bootstrap-grid.css.map │ │ │ ├── bootstrap-grid.min.css │ │ │ ├── bootstrap-grid.min.css.map │ │ │ ├── bootstrap-grid.rtl.css │ │ │ ├── bootstrap-grid.rtl.css.map │ │ │ ├── bootstrap-grid.rtl.min.css │ │ │ ├── bootstrap-grid.rtl.min.css.map │ │ │ ├── bootstrap-reboot.css │ │ │ ├── bootstrap-reboot.css.map │ │ │ ├── bootstrap-reboot.min.css │ │ │ ├── bootstrap-reboot.min.css.map │ │ │ ├── bootstrap-reboot.rtl.css │ │ │ ├── bootstrap-reboot.rtl.css.map │ │ │ ├── bootstrap-reboot.rtl.min.css │ │ │ ├── bootstrap-reboot.rtl.min.css.map │ │ │ ├── bootstrap-utilities.css │ │ │ ├── bootstrap-utilities.css.map │ │ │ ├── bootstrap-utilities.min.css │ │ │ ├── bootstrap-utilities.min.css.map │ │ │ ├── bootstrap-utilities.rtl.css │ │ │ ├── bootstrap-utilities.rtl.css.map │ │ │ ├── bootstrap-utilities.rtl.min.css │ │ │ ├── bootstrap-utilities.rtl.min.css.map │ │ │ ├── bootstrap.css │ │ │ ├── bootstrap.css.map │ │ │ ├── bootstrap.min.css │ │ │ ├── bootstrap.min.css.map │ │ │ ├── bootstrap.rtl.css │ │ │ ├── bootstrap.rtl.css.map │ │ │ ├── bootstrap.rtl.min.css │ │ │ └── bootstrap.rtl.min.css.map │ │ │ └── js │ │ │ ├── bootstrap.bundle.js │ │ │ ├── bootstrap.bundle.js.map │ │ │ ├── bootstrap.bundle.min.js │ │ │ ├── bootstrap.bundle.min.js.map │ │ │ ├── bootstrap.esm.js │ │ │ ├── bootstrap.esm.js.map │ │ │ ├── bootstrap.esm.min.js │ │ │ ├── bootstrap.esm.min.js.map │ │ │ ├── bootstrap.js │ │ │ ├── bootstrap.js.map │ │ │ ├── bootstrap.min.js │ │ │ └── bootstrap.min.js.map │ │ ├── jquery-validation-unobtrusive │ │ ├── LICENSE.txt │ │ ├── jquery.validate.unobtrusive.js │ │ └── jquery.validate.unobtrusive.min.js │ │ ├── jquery-validation │ │ ├── LICENSE.md │ │ └── dist │ │ │ ├── additional-methods.js │ │ │ ├── additional-methods.min.js │ │ │ ├── jquery.validate.js │ │ │ └── jquery.validate.min.js │ │ └── jquery │ │ ├── LICENSE.txt │ │ └── dist │ │ ├── jquery.js │ │ ├── jquery.min.js │ │ └── jquery.min.map ├── MiddlewareDemo │ ├── ClientInfoRepository │ │ ├── ClientInfoRepository.cs │ │ └── IClientInfoRepository.cs │ ├── Controllers │ │ └── ClientInfoController.cs │ ├── GlobalUsings.cs │ ├── Middleware │ │ ├── ClientInfoMiddleware.cs │ │ ├── ClientInfoMiddlewareExtensions.cs │ │ ├── MyHttpsRedirectionMiddleware.cs │ │ └── MyHttpsRedirectionMiddlewareExtensions.cs │ ├── MiddlewareDemo.csproj │ ├── MiddlewareDemo.sln │ ├── Models │ │ └── ClientInfo.cs │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── appsettings.Development.json │ └── appsettings.json ├── MyOidcServer │ ├── MyOidcServer.sln │ ├── MyOidcServer.slnLaunch.user │ ├── OidcServer │ │ ├── Controllers │ │ │ ├── AuthorizeController.cs │ │ │ └── HomeController.cs │ │ ├── Helpers │ │ │ ├── JwkLoader.cs │ │ │ └── JwtGenerator.cs │ │ ├── Models │ │ │ ├── AuthenticationRequestModel.cs │ │ │ ├── AuthenticationResponseModel.cs │ │ │ ├── CodeFlowResponseModel.cs │ │ │ ├── CodeFlowResponseViewModel.cs │ │ │ ├── CodeItem.cs │ │ │ ├── ErrorViewModel.cs │ │ │ ├── RefreshResponseModel.cs │ │ │ └── User.cs │ │ ├── OidcDiscovery │ │ │ ├── default-jwk.json │ │ │ ├── jwks.json │ │ │ └── openid-configuration.json │ │ ├── OidcServer.csproj │ │ ├── OidcServer.csproj.user │ │ ├── Program.cs │ │ ├── Properties │ │ │ └── launchSettings.json │ │ ├── Repositories │ │ │ ├── CodeItemRepository.cs │ │ │ ├── ICodeItemRepository.cs │ │ │ ├── IUserRepository.cs │ │ │ └── InMemoryUserRepository.cs │ │ ├── Views │ │ │ ├── Authorize │ │ │ │ ├── Index.cshtml │ │ │ │ ├── SubmitForm.cshtml │ │ │ │ └── UserNotFound.cshtml │ │ │ ├── Home │ │ │ │ ├── Index.cshtml │ │ │ │ └── Privacy.cshtml │ │ │ ├── Shared │ │ │ │ ├── Error.cshtml │ │ │ │ ├── _Layout.cshtml │ │ │ │ ├── _Layout.cshtml.css │ │ │ │ └── _ValidationScriptsPartial.cshtml │ │ │ ├── _ViewImports.cshtml │ │ │ └── _ViewStart.cshtml │ │ ├── appsettings.Development.json │ │ ├── appsettings.json │ │ └── wwwroot │ │ │ ├── css │ │ │ └── site.css │ │ │ ├── favicon.ico │ │ │ ├── js │ │ │ └── site.js │ │ │ └── lib │ │ │ ├── bootstrap │ │ │ ├── LICENSE │ │ │ └── dist │ │ │ │ ├── css │ │ │ │ ├── bootstrap-grid.css │ │ │ │ ├── bootstrap-grid.css.map │ │ │ │ ├── bootstrap-grid.min.css │ │ │ │ ├── bootstrap-grid.min.css.map │ │ │ │ ├── bootstrap-grid.rtl.css │ │ │ │ ├── bootstrap-grid.rtl.css.map │ │ │ │ ├── bootstrap-grid.rtl.min.css │ │ │ │ ├── bootstrap-grid.rtl.min.css.map │ │ │ │ ├── bootstrap-reboot.css │ │ │ │ ├── bootstrap-reboot.css.map │ │ │ │ ├── bootstrap-reboot.min.css │ │ │ │ ├── bootstrap-reboot.min.css.map │ │ │ │ ├── bootstrap-reboot.rtl.css │ │ │ │ ├── bootstrap-reboot.rtl.css.map │ │ │ │ ├── bootstrap-reboot.rtl.min.css │ │ │ │ ├── bootstrap-reboot.rtl.min.css.map │ │ │ │ ├── bootstrap-utilities.css │ │ │ │ ├── bootstrap-utilities.css.map │ │ │ │ ├── bootstrap-utilities.min.css │ │ │ │ ├── bootstrap-utilities.min.css.map │ │ │ │ ├── bootstrap-utilities.rtl.css │ │ │ │ ├── bootstrap-utilities.rtl.css.map │ │ │ │ ├── bootstrap-utilities.rtl.min.css │ │ │ │ ├── bootstrap-utilities.rtl.min.css.map │ │ │ │ ├── bootstrap.css │ │ │ │ ├── bootstrap.css.map │ │ │ │ ├── bootstrap.min.css │ │ │ │ ├── bootstrap.min.css.map │ │ │ │ ├── bootstrap.rtl.css │ │ │ │ ├── bootstrap.rtl.css.map │ │ │ │ ├── bootstrap.rtl.min.css │ │ │ │ └── bootstrap.rtl.min.css.map │ │ │ │ └── js │ │ │ │ ├── bootstrap.bundle.js │ │ │ │ ├── bootstrap.bundle.js.map │ │ │ │ ├── bootstrap.bundle.min.js │ │ │ │ ├── bootstrap.bundle.min.js.map │ │ │ │ ├── bootstrap.esm.js │ │ │ │ ├── bootstrap.esm.js.map │ │ │ │ ├── bootstrap.esm.min.js │ │ │ │ ├── bootstrap.esm.min.js.map │ │ │ │ ├── bootstrap.js │ │ │ │ ├── bootstrap.js.map │ │ │ │ ├── bootstrap.min.js │ │ │ │ └── bootstrap.min.js.map │ │ │ ├── jquery-validation-unobtrusive │ │ │ ├── LICENSE.txt │ │ │ ├── jquery.validate.unobtrusive.js │ │ │ └── jquery.validate.unobtrusive.min.js │ │ │ ├── jquery-validation │ │ │ ├── LICENSE.md │ │ │ └── dist │ │ │ │ ├── additional-methods.js │ │ │ │ ├── additional-methods.min.js │ │ │ │ ├── jquery.validate.js │ │ │ │ └── jquery.validate.min.js │ │ │ └── jquery │ │ │ ├── LICENSE.txt │ │ │ └── dist │ │ │ ├── jquery.js │ │ │ ├── jquery.min.js │ │ │ └── jquery.min.map │ └── OidcWebClient │ │ ├── Controllers │ │ ├── HomeController.cs │ │ └── ProfileController.cs │ │ ├── Models │ │ └── ErrorViewModel.cs │ │ ├── OidcWebClient.csproj │ │ ├── OidcWebClient.csproj.user │ │ ├── Program.cs │ │ ├── Properties │ │ └── launchSettings.json │ │ ├── Views │ │ ├── Home │ │ │ ├── Index.cshtml │ │ │ └── Privacy.cshtml │ │ ├── Profile │ │ │ └── Index.cshtml │ │ ├── Shared │ │ │ ├── Error.cshtml │ │ │ ├── _Layout.cshtml │ │ │ ├── _Layout.cshtml.css │ │ │ └── _ValidationScriptsPartial.cshtml │ │ ├── _ViewImports.cshtml │ │ └── _ViewStart.cshtml │ │ ├── appsettings.Development.json │ │ ├── appsettings.json │ │ └── wwwroot │ │ ├── css │ │ └── site.css │ │ ├── favicon.ico │ │ ├── js │ │ └── site.js │ │ └── lib │ │ ├── bootstrap │ │ ├── LICENSE │ │ └── dist │ │ │ ├── css │ │ │ ├── bootstrap-grid.css │ │ │ ├── bootstrap-grid.css.map │ │ │ ├── bootstrap-grid.min.css │ │ │ ├── bootstrap-grid.min.css.map │ │ │ ├── bootstrap-grid.rtl.css │ │ │ ├── bootstrap-grid.rtl.css.map │ │ │ ├── bootstrap-grid.rtl.min.css │ │ │ ├── bootstrap-grid.rtl.min.css.map │ │ │ ├── bootstrap-reboot.css │ │ │ ├── bootstrap-reboot.css.map │ │ │ ├── bootstrap-reboot.min.css │ │ │ ├── bootstrap-reboot.min.css.map │ │ │ ├── bootstrap-reboot.rtl.css │ │ │ ├── bootstrap-reboot.rtl.css.map │ │ │ ├── bootstrap-reboot.rtl.min.css │ │ │ ├── bootstrap-reboot.rtl.min.css.map │ │ │ ├── bootstrap-utilities.css │ │ │ ├── bootstrap-utilities.css.map │ │ │ ├── bootstrap-utilities.min.css │ │ │ ├── bootstrap-utilities.min.css.map │ │ │ ├── bootstrap-utilities.rtl.css │ │ │ ├── bootstrap-utilities.rtl.css.map │ │ │ ├── bootstrap-utilities.rtl.min.css │ │ │ ├── bootstrap-utilities.rtl.min.css.map │ │ │ ├── bootstrap.css │ │ │ ├── bootstrap.css.map │ │ │ ├── bootstrap.min.css │ │ │ ├── bootstrap.min.css.map │ │ │ ├── bootstrap.rtl.css │ │ │ ├── bootstrap.rtl.css.map │ │ │ ├── bootstrap.rtl.min.css │ │ │ └── bootstrap.rtl.min.css.map │ │ │ └── js │ │ │ ├── bootstrap.bundle.js │ │ │ ├── bootstrap.bundle.js.map │ │ │ ├── bootstrap.bundle.min.js │ │ │ ├── bootstrap.bundle.min.js.map │ │ │ ├── bootstrap.esm.js │ │ │ ├── bootstrap.esm.js.map │ │ │ ├── bootstrap.esm.min.js │ │ │ ├── bootstrap.esm.min.js.map │ │ │ ├── bootstrap.js │ │ │ ├── bootstrap.js.map │ │ │ ├── bootstrap.min.js │ │ │ └── bootstrap.min.js.map │ │ ├── jquery-validation-unobtrusive │ │ ├── LICENSE.txt │ │ ├── jquery.validate.unobtrusive.js │ │ └── jquery.validate.unobtrusive.min.js │ │ ├── jquery-validation │ │ ├── LICENSE.md │ │ └── dist │ │ │ ├── additional-methods.js │ │ │ ├── additional-methods.min.js │ │ │ ├── jquery.validate.js │ │ │ └── jquery.validate.min.js │ │ └── jquery │ │ ├── LICENSE.txt │ │ └── dist │ │ ├── jquery.js │ │ ├── jquery.min.js │ │ └── jquery.min.map ├── MySession │ ├── MySession.sln │ ├── MySession │ │ ├── Controllers │ │ │ ├── HomeController.cs │ │ │ └── TestController.cs │ │ ├── GlobalUsings.cs │ │ ├── Models │ │ │ └── ErrorViewModel.cs │ │ ├── MySession.csproj │ │ ├── MySession.csproj.user │ │ ├── MySession │ │ │ ├── FileMySessionStorageEngine.cs │ │ │ ├── IMySessionStorage.cs │ │ │ ├── IMySessionStorageEngine.cs │ │ │ ├── MySession.cs │ │ │ ├── MySessionExtensions.cs │ │ │ ├── MySessionRegistrationExtensions.cs │ │ │ ├── MySessionScopedContainer.cs │ │ │ └── MySessionStorage.cs │ │ ├── Program.cs │ │ ├── Properties │ │ │ └── launchSettings.json │ │ ├── Views │ │ │ ├── Home │ │ │ │ ├── Index.cshtml │ │ │ │ └── Privacy.cshtml │ │ │ ├── Shared │ │ │ │ ├── Error.cshtml │ │ │ │ ├── _Layout.cshtml │ │ │ │ ├── _Layout.cshtml.css │ │ │ │ └── _ValidationScriptsPartial.cshtml │ │ │ ├── _ViewImports.cshtml │ │ │ └── _ViewStart.cshtml │ │ ├── appsettings.Development.json │ │ ├── appsettings.json │ │ └── wwwroot │ │ │ ├── css │ │ │ └── site.css │ │ │ ├── favicon.ico │ │ │ ├── js │ │ │ └── site.js │ │ │ └── lib │ │ │ ├── bootstrap │ │ │ ├── LICENSE │ │ │ └── dist │ │ │ │ ├── css │ │ │ │ ├── bootstrap-grid.css │ │ │ │ ├── bootstrap-grid.css.map │ │ │ │ ├── bootstrap-grid.min.css │ │ │ │ ├── bootstrap-grid.min.css.map │ │ │ │ ├── bootstrap-grid.rtl.css │ │ │ │ ├── bootstrap-grid.rtl.css.map │ │ │ │ ├── bootstrap-grid.rtl.min.css │ │ │ │ ├── bootstrap-grid.rtl.min.css.map │ │ │ │ ├── bootstrap-reboot.css │ │ │ │ ├── bootstrap-reboot.css.map │ │ │ │ ├── bootstrap-reboot.min.css │ │ │ │ ├── bootstrap-reboot.min.css.map │ │ │ │ ├── bootstrap-reboot.rtl.css │ │ │ │ ├── bootstrap-reboot.rtl.css.map │ │ │ │ ├── bootstrap-reboot.rtl.min.css │ │ │ │ ├── bootstrap-reboot.rtl.min.css.map │ │ │ │ ├── bootstrap-utilities.css │ │ │ │ ├── bootstrap-utilities.css.map │ │ │ │ ├── bootstrap-utilities.min.css │ │ │ │ ├── bootstrap-utilities.min.css.map │ │ │ │ ├── bootstrap-utilities.rtl.css │ │ │ │ ├── bootstrap-utilities.rtl.css.map │ │ │ │ ├── bootstrap-utilities.rtl.min.css │ │ │ │ ├── bootstrap-utilities.rtl.min.css.map │ │ │ │ ├── bootstrap.css │ │ │ │ ├── bootstrap.css.map │ │ │ │ ├── bootstrap.min.css │ │ │ │ ├── bootstrap.min.css.map │ │ │ │ ├── bootstrap.rtl.css │ │ │ │ ├── bootstrap.rtl.css.map │ │ │ │ ├── bootstrap.rtl.min.css │ │ │ │ └── bootstrap.rtl.min.css.map │ │ │ │ └── js │ │ │ │ ├── bootstrap.bundle.js │ │ │ │ ├── bootstrap.bundle.js.map │ │ │ │ ├── bootstrap.bundle.min.js │ │ │ │ ├── bootstrap.bundle.min.js.map │ │ │ │ ├── bootstrap.esm.js │ │ │ │ ├── bootstrap.esm.js.map │ │ │ │ ├── bootstrap.esm.min.js │ │ │ │ ├── bootstrap.esm.min.js.map │ │ │ │ ├── bootstrap.js │ │ │ │ ├── bootstrap.js.map │ │ │ │ ├── bootstrap.min.js │ │ │ │ └── bootstrap.min.js.map │ │ │ ├── jquery-validation-unobtrusive │ │ │ ├── LICENSE.txt │ │ │ ├── jquery.validate.unobtrusive.js │ │ │ └── jquery.validate.unobtrusive.min.js │ │ │ ├── jquery-validation │ │ │ ├── LICENSE.md │ │ │ └── dist │ │ │ │ ├── additional-methods.js │ │ │ │ ├── additional-methods.min.js │ │ │ │ ├── jquery.validate.js │ │ │ │ └── jquery.validate.min.js │ │ │ └── jquery │ │ │ ├── LICENSE.txt │ │ │ └── dist │ │ │ ├── jquery.js │ │ │ ├── jquery.min.js │ │ │ └── jquery.min.map │ └── MySessionIntegrationTest │ │ ├── MySessionIntegrationTest.csproj │ │ └── SessionTests.cs ├── SecurityDemo │ ├── .gitignore │ ├── AccountDemo │ │ ├── AccountDemo.csproj │ │ ├── Controllers │ │ │ ├── AccountController.cs │ │ │ ├── HomeController.cs │ │ │ └── ProfileController.cs │ │ ├── Models │ │ │ ├── ErrorViewModel.cs │ │ │ ├── LogOnModel.cs │ │ │ ├── RegisterModel.cs │ │ │ └── UserProfileModel.cs │ │ ├── Program.cs │ │ ├── Properties │ │ │ └── launchSettings.json │ │ ├── Views │ │ │ ├── Account │ │ │ │ ├── LogOn.cshtml │ │ │ │ └── Register.cshtml │ │ │ ├── Home │ │ │ │ ├── Index.cshtml │ │ │ │ └── Privacy.cshtml │ │ │ ├── Profile │ │ │ │ └── Index.cshtml │ │ │ ├── Shared │ │ │ │ ├── Error.cshtml │ │ │ │ ├── _Layout.cshtml │ │ │ │ ├── _Layout.cshtml.css │ │ │ │ └── _ValidationScriptsPartial.cshtml │ │ │ ├── _ViewImports.cshtml │ │ │ └── _ViewStart.cshtml │ │ ├── appsettings.Development.json │ │ ├── appsettings.json │ │ └── wwwroot │ │ │ ├── css │ │ │ └── site.css │ │ │ ├── favicon.ico │ │ │ ├── js │ │ │ └── site.js │ │ │ └── lib │ │ │ ├── bootstrap │ │ │ ├── LICENSE │ │ │ └── dist │ │ │ │ ├── css │ │ │ │ ├── bootstrap-grid.css │ │ │ │ ├── bootstrap-grid.css.map │ │ │ │ ├── bootstrap-grid.min.css │ │ │ │ ├── bootstrap-grid.min.css.map │ │ │ │ ├── bootstrap-grid.rtl.css │ │ │ │ ├── bootstrap-grid.rtl.css.map │ │ │ │ ├── bootstrap-grid.rtl.min.css │ │ │ │ ├── bootstrap-grid.rtl.min.css.map │ │ │ │ ├── bootstrap-reboot.css │ │ │ │ ├── bootstrap-reboot.css.map │ │ │ │ ├── bootstrap-reboot.min.css │ │ │ │ ├── bootstrap-reboot.min.css.map │ │ │ │ ├── bootstrap-reboot.rtl.css │ │ │ │ ├── bootstrap-reboot.rtl.css.map │ │ │ │ ├── bootstrap-reboot.rtl.min.css │ │ │ │ ├── bootstrap-reboot.rtl.min.css.map │ │ │ │ ├── bootstrap-utilities.css │ │ │ │ ├── bootstrap-utilities.css.map │ │ │ │ ├── bootstrap-utilities.min.css │ │ │ │ ├── bootstrap-utilities.min.css.map │ │ │ │ ├── bootstrap-utilities.rtl.css │ │ │ │ ├── bootstrap-utilities.rtl.css.map │ │ │ │ ├── bootstrap-utilities.rtl.min.css │ │ │ │ ├── bootstrap-utilities.rtl.min.css.map │ │ │ │ ├── bootstrap.css │ │ │ │ ├── bootstrap.css.map │ │ │ │ ├── bootstrap.min.css │ │ │ │ ├── bootstrap.min.css.map │ │ │ │ ├── bootstrap.rtl.css │ │ │ │ ├── bootstrap.rtl.css.map │ │ │ │ ├── bootstrap.rtl.min.css │ │ │ │ └── bootstrap.rtl.min.css.map │ │ │ │ └── js │ │ │ │ ├── bootstrap.bundle.js │ │ │ │ ├── bootstrap.bundle.js.map │ │ │ │ ├── bootstrap.bundle.min.js │ │ │ │ ├── bootstrap.bundle.min.js.map │ │ │ │ ├── bootstrap.esm.js │ │ │ │ ├── bootstrap.esm.js.map │ │ │ │ ├── bootstrap.esm.min.js │ │ │ │ ├── bootstrap.esm.min.js.map │ │ │ │ ├── bootstrap.js │ │ │ │ ├── bootstrap.js.map │ │ │ │ ├── bootstrap.min.js │ │ │ │ └── bootstrap.min.js.map │ │ │ ├── jquery-validation-unobtrusive │ │ │ ├── LICENSE.txt │ │ │ ├── jquery.validate.unobtrusive.js │ │ │ └── jquery.validate.unobtrusive.min.js │ │ │ ├── jquery-validation │ │ │ ├── LICENSE.md │ │ │ └── dist │ │ │ │ ├── additional-methods.js │ │ │ │ ├── additional-methods.min.js │ │ │ │ ├── jquery.validate.js │ │ │ │ └── jquery.validate.min.js │ │ │ └── jquery │ │ │ ├── LICENSE.txt │ │ │ └── dist │ │ │ ├── jquery.js │ │ │ ├── jquery.min.js │ │ │ └── jquery.min.map │ ├── SecurityDemo.sln │ └── UserStorage │ │ ├── IUserRepository.cs │ │ ├── JsonFileUserRepository.cs │ │ ├── JsonFileUserRepositoryOptions.cs │ │ ├── User.cs │ │ └── UserStorage.csproj ├── TodoApi │ ├── IntegrationTests │ │ ├── ApiIntegrationTests.cs │ │ └── IntegrationTests.csproj │ ├── RepositoryTests │ │ ├── MOngoDbRepositoryUnitTest.cs │ │ └── RepositoryTests.csproj │ ├── ToDoRepository.Abstractions │ │ ├── IToDoRepository.cs │ │ ├── ToDoItem.cs │ │ └── ToDoRepository.Abstractions.csproj │ ├── ToDoRepository.MongoDb │ │ ├── MongoDbToDoRepository.cs │ │ ├── MongoDbToDoRepositoryOptions.cs │ │ └── ToDoRepository.MongoDb.csproj │ ├── TodoApi.sln │ └── TodoApi │ │ ├── Controllers │ │ └── TodoController.cs │ │ ├── Program.cs │ │ ├── Properties │ │ └── launchSettings.json │ │ ├── TodoApi.csproj │ │ ├── TodoApi.csproj.user │ │ ├── TodoApi.http │ │ ├── appsettings.Development.json │ │ └── appsettings.json └── TodoList │ ├── .gitignore │ ├── Entities │ ├── Entities.csproj │ └── TodoItem.cs │ ├── Infratructure │ ├── InMemoryToDoItemRepository.cs │ └── Infratructure.csproj │ ├── TestProject │ ├── TestProject.csproj │ └── UnitTest1.cs │ ├── TodoList.sln │ ├── TodoList │ ├── Controllers │ │ └── HomeController.cs │ ├── GlobalUsings.cs │ ├── Models │ │ ├── ErrorViewModel.cs │ │ ├── Item.cs │ │ └── TodoListViewModel.cs │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── TodoList.csproj │ ├── TodoList.csproj.user │ ├── Views │ │ ├── Home │ │ │ ├── Add.cshtml │ │ │ └── Index.cshtml │ │ ├── Shared │ │ │ ├── Error.cshtml │ │ │ ├── _Layout.cshtml │ │ │ ├── _Layout.cshtml.css │ │ │ └── _ValidationScriptsPartial.cshtml │ │ ├── _ViewImports.cshtml │ │ └── _ViewStart.cshtml │ ├── appsettings.Development.json │ ├── appsettings.json │ └── wwwroot │ │ ├── css │ │ └── site.css │ │ ├── favicon.ico │ │ ├── js │ │ └── site.js │ │ └── lib │ │ ├── bootstrap │ │ ├── LICENSE │ │ └── dist │ │ │ ├── css │ │ │ ├── bootstrap-grid.css │ │ │ ├── bootstrap-grid.css.map │ │ │ ├── bootstrap-grid.min.css │ │ │ ├── bootstrap-grid.min.css.map │ │ │ ├── bootstrap-grid.rtl.css │ │ │ ├── bootstrap-grid.rtl.css.map │ │ │ ├── bootstrap-grid.rtl.min.css │ │ │ ├── bootstrap-grid.rtl.min.css.map │ │ │ ├── bootstrap-reboot.css │ │ │ ├── bootstrap-reboot.css.map │ │ │ ├── bootstrap-reboot.min.css │ │ │ ├── bootstrap-reboot.min.css.map │ │ │ ├── bootstrap-reboot.rtl.css │ │ │ ├── bootstrap-reboot.rtl.css.map │ │ │ ├── bootstrap-reboot.rtl.min.css │ │ │ ├── bootstrap-reboot.rtl.min.css.map │ │ │ ├── bootstrap-utilities.css │ │ │ ├── bootstrap-utilities.css.map │ │ │ ├── bootstrap-utilities.min.css │ │ │ ├── bootstrap-utilities.min.css.map │ │ │ ├── bootstrap-utilities.rtl.css │ │ │ ├── bootstrap-utilities.rtl.css.map │ │ │ ├── bootstrap-utilities.rtl.min.css │ │ │ ├── bootstrap-utilities.rtl.min.css.map │ │ │ ├── bootstrap.css │ │ │ ├── bootstrap.css.map │ │ │ ├── bootstrap.min.css │ │ │ ├── bootstrap.min.css.map │ │ │ ├── bootstrap.rtl.css │ │ │ ├── bootstrap.rtl.css.map │ │ │ ├── bootstrap.rtl.min.css │ │ │ └── bootstrap.rtl.min.css.map │ │ │ └── js │ │ │ ├── bootstrap.bundle.js │ │ │ ├── bootstrap.bundle.js.map │ │ │ ├── bootstrap.bundle.min.js │ │ │ ├── bootstrap.bundle.min.js.map │ │ │ ├── bootstrap.esm.js │ │ │ ├── bootstrap.esm.js.map │ │ │ ├── bootstrap.esm.min.js │ │ │ ├── bootstrap.esm.min.js.map │ │ │ ├── bootstrap.js │ │ │ ├── bootstrap.js.map │ │ │ ├── bootstrap.min.js │ │ │ └── bootstrap.min.js.map │ │ ├── jquery-validation-unobtrusive │ │ ├── LICENSE.txt │ │ ├── jquery.validate.unobtrusive.js │ │ └── jquery.validate.unobtrusive.min.js │ │ ├── jquery-validation │ │ ├── LICENSE.md │ │ └── dist │ │ │ ├── additional-methods.js │ │ │ ├── additional-methods.min.js │ │ │ ├── jquery.validate.js │ │ │ └── jquery.validate.min.js │ │ └── jquery │ │ ├── LICENSE.txt │ │ └── dist │ │ ├── jquery.js │ │ ├── jquery.min.js │ │ └── jquery.min.map │ └── UseCases │ ├── IToDoItemRepository.cs │ ├── TodoListManager.cs │ └── UseCases.csproj └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # This .gitignore file was automatically created by Microsoft(R) Visual Studio. 3 | ################################################################################ 4 | 5 | .vs 6 | obj 7 | bin 8 | /Projects/MySession/MySession/sessions 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Dao Hai Nam 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Projects/JwtDemo/Controllers/ApiController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | using Microsoft.AspNetCore.Mvc; 3 | 4 | namespace JwtDemo.Controllers 5 | { 6 | [Authorize] 7 | public class ApiController : Controller 8 | { 9 | 10 | public IActionResult SayHello(string name) 11 | { 12 | return Content($"Hello {name}!"); 13 | } 14 | [Authorize(Roles = "Role1")] 15 | public IActionResult SayHello1(string name) 16 | { 17 | return Content($"Hello {name}!"); 18 | } 19 | [Authorize(Roles = "Role1,Role2")] 20 | public IActionResult SayHello2(string name) 21 | { 22 | return Content($"Hello {name}!"); 23 | } 24 | [Authorize(Roles = "Role1")] 25 | [Authorize(Roles = "Role2")] 26 | public IActionResult SayHello3(string name) 27 | { 28 | return Content($"Hello {name}!"); 29 | } 30 | public IActionResult SayHello4(string name) 31 | { 32 | return Content($"Hello {name}!"); 33 | } 34 | [AllowAnonymous] 35 | public IActionResult HelloAnonymous() 36 | { 37 | return Content($"Hello Anonymous!"); 38 | } 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Projects/JwtDemo/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using JwtDemo.Models; 3 | using Microsoft.AspNetCore.Mvc; 4 | 5 | namespace JwtDemo.Controllers 6 | { 7 | public class HomeController : Controller 8 | { 9 | private readonly ILogger _logger; 10 | 11 | public HomeController(ILogger logger) 12 | { 13 | _logger = logger; 14 | } 15 | 16 | public IActionResult Index() 17 | { 18 | return View(); 19 | } 20 | 21 | public IActionResult Privacy() 22 | { 23 | return View(); 24 | } 25 | 26 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] 27 | public IActionResult Error() 28 | { 29 | return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Projects/JwtDemo/Controllers/PbApiController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | using Microsoft.AspNetCore.Mvc; 3 | 4 | namespace JwtDemo.Controllers 5 | { 6 | public class PbApiController : Controller 7 | { 8 | [Authorize(Policy = "Policy1")] 9 | public IActionResult SayHello(string name) 10 | { 11 | return Content($"Hello {name}!"); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Projects/JwtDemo/JwtDemo.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Projects/JwtDemo/Models/ErrorViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace JwtDemo.Models 2 | { 3 | public class ErrorViewModel 4 | { 5 | public string? RequestId { get; set; } 6 | 7 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Projects/JwtDemo/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:37468", 8 | "sslPort": 44336 9 | } 10 | }, 11 | "profiles": { 12 | "http": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "applicationUrl": "http://localhost:5248", 17 | "environmentVariables": { 18 | "ASPNETCORE_ENVIRONMENT": "Development" 19 | } 20 | }, 21 | "https": { 22 | "commandName": "Project", 23 | "dotnetRunMessages": true, 24 | "launchBrowser": true, 25 | "applicationUrl": "https://localhost:7075;http://localhost:5248", 26 | "environmentVariables": { 27 | "ASPNETCORE_ENVIRONMENT": "Development" 28 | } 29 | }, 30 | "IIS Express": { 31 | "commandName": "IISExpress", 32 | "launchBrowser": true, 33 | "environmentVariables": { 34 | "ASPNETCORE_ENVIRONMENT": "Development" 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Projects/JwtDemo/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Home Page"; 3 | } 4 | 5 |
6 |

Welcome

7 |

Learn about building Web apps with ASP.NET Core.

8 |
9 | -------------------------------------------------------------------------------- /Projects/JwtDemo/Views/Home/Privacy.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Privacy Policy"; 3 | } 4 |

@ViewData["Title"]

5 | 6 |

Use this page to detail your site's privacy policy.

7 | -------------------------------------------------------------------------------- /Projects/JwtDemo/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @model ErrorViewModel 2 | @{ 3 | ViewData["Title"] = "Error"; 4 | } 5 | 6 |

Error.

7 |

An error occurred while processing your request.

8 | 9 | @if (Model.ShowRequestId) 10 | { 11 |

12 | Request ID: @Model.RequestId 13 |

14 | } 15 | 16 |

Development Mode

17 |

18 | Swapping to Development environment will display more detailed information about the error that occurred. 19 |

20 |

21 | The Development environment shouldn't be enabled for deployed applications. 22 | It can result in displaying sensitive information from exceptions to end users. 23 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development 24 | and restarting the app. 25 |

26 | -------------------------------------------------------------------------------- /Projects/JwtDemo/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewData["Title"] - JwtDemo 7 | 8 | 9 | 10 | 11 | 12 |
13 | 32 |
33 |
34 |
35 | @RenderBody() 36 |
37 |
38 | 39 |
40 |
41 | © 2024 - JwtDemo - Privacy 42 |
43 |
44 | 45 | 46 | 47 | @await RenderSectionAsync("Scripts", required: false) 48 | 49 | 50 | -------------------------------------------------------------------------------- /Projects/JwtDemo/Views/Shared/_Layout.cshtml.css: -------------------------------------------------------------------------------- 1 | /* Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | for details on configuring this project to bundle and minify static web assets. */ 3 | 4 | a.navbar-brand { 5 | white-space: normal; 6 | text-align: center; 7 | word-break: break-all; 8 | } 9 | 10 | a { 11 | color: #0077cc; 12 | } 13 | 14 | .btn-primary { 15 | color: #fff; 16 | background-color: #1b6ec2; 17 | border-color: #1861ac; 18 | } 19 | 20 | .nav-pills .nav-link.active, .nav-pills .show > .nav-link { 21 | color: #fff; 22 | background-color: #1b6ec2; 23 | border-color: #1861ac; 24 | } 25 | 26 | .border-top { 27 | border-top: 1px solid #e5e5e5; 28 | } 29 | .border-bottom { 30 | border-bottom: 1px solid #e5e5e5; 31 | } 32 | 33 | .box-shadow { 34 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05); 35 | } 36 | 37 | button.accept-policy { 38 | font-size: 1rem; 39 | line-height: inherit; 40 | } 41 | 42 | .footer { 43 | position: absolute; 44 | bottom: 0; 45 | width: 100%; 46 | white-space: nowrap; 47 | line-height: 60px; 48 | } 49 | -------------------------------------------------------------------------------- /Projects/JwtDemo/Views/Shared/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /Projects/JwtDemo/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using JwtDemo 2 | @using JwtDemo.Models 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | -------------------------------------------------------------------------------- /Projects/JwtDemo/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /Projects/JwtDemo/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Projects/JwtDemo/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /Projects/JwtDemo/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-size: 14px; 3 | } 4 | 5 | @media (min-width: 768px) { 6 | html { 7 | font-size: 16px; 8 | } 9 | } 10 | 11 | .btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus { 12 | box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb; 13 | } 14 | 15 | html { 16 | position: relative; 17 | min-height: 100%; 18 | } 19 | 20 | body { 21 | margin-bottom: 60px; 22 | } -------------------------------------------------------------------------------- /Projects/JwtDemo/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daohainam/lets-learn-aspnet/ee9bcdf96c487cd2a270c660f5ff468f776241a0/Projects/JwtDemo/wwwroot/favicon.ico -------------------------------------------------------------------------------- /Projects/JwtDemo/wwwroot/js/site.js: -------------------------------------------------------------------------------- 1 | // Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | // for details on configuring this project to bundle and minify static web assets. 3 | 4 | // Write your JavaScript code. 5 | -------------------------------------------------------------------------------- /Projects/JwtDemo/wwwroot/lib/bootstrap/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2021 Twitter, Inc. 4 | Copyright (c) 2011-2021 The Bootstrap Authors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Projects/JwtDemo/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) .NET Foundation and Contributors 4 | 5 | All rights reserved. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /Projects/JwtDemo/wwwroot/lib/jquery-validation/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright Jörn Zaefferer 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Projects/JwtDemo/wwwroot/lib/jquery/LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Copyright OpenJS Foundation and other contributors, https://openjsf.org/ 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Projects/MiddlewareDemo/ClientInfoRepository/ClientInfoRepository.cs: -------------------------------------------------------------------------------- 1 | namespace MiddlewareDemo.ClientInfoRepository 2 | { 3 | public class ClientInfoRepository : IClientInfoRepository 4 | { 5 | public ClientInfo? GetClientInfo(string apiKey) 6 | { 7 | if (_clientInfos.ContainsKey(apiKey)) 8 | { 9 | return _clientInfos[apiKey]; 10 | } 11 | 12 | return null; 13 | } 14 | 15 | private Dictionary _clientInfos = new Dictionary 16 | { 17 | { "123", new ClientInfo { Id = 1, Name = "Client 1" } }, 18 | { "456", new ClientInfo { Id = 2, Name = "Client 2" } }, 19 | { "789", new ClientInfo { Id = 3, Name = "Client 3" } } 20 | }; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Projects/MiddlewareDemo/ClientInfoRepository/IClientInfoRepository.cs: -------------------------------------------------------------------------------- 1 | namespace MiddlewareDemo.ClientInfoRepository 2 | { 3 | public interface IClientInfoRepository 4 | { 5 | ClientInfo? GetClientInfo(string apiKey); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Projects/MiddlewareDemo/Controllers/ClientInfoController.cs: -------------------------------------------------------------------------------- 1 | namespace MiddlewareDemo.Controllers 2 | { 3 | public class ClientInfoController : Controller 4 | { 5 | private readonly IClientInfoRepository _clientInfoRepository; 6 | 7 | public ClientInfoController(IClientInfoRepository clientInfoRepository) { 8 | _clientInfoRepository = clientInfoRepository; 9 | } 10 | 11 | 12 | [Route("/clientinfo")] 13 | [HttpGet] 14 | public IActionResult GetClientInfo() 15 | { 16 | return Ok(HttpContext.Features.Get()); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Projects/MiddlewareDemo/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using Microsoft.AspNetCore.Mvc; 2 | global using MiddlewareDemo.ClientInfoRepository; 3 | global using MiddlewareDemo.Middleware; 4 | global using MiddlewareDemo.Models; -------------------------------------------------------------------------------- /Projects/MiddlewareDemo/Middleware/ClientInfoMiddleware.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.DataProtection.KeyManagement; 2 | 3 | namespace MiddlewareDemo.Middleware 4 | { 5 | public class ClientInfoMiddleware 6 | { 7 | private readonly RequestDelegate _next; 8 | private readonly ILogger _logger; 9 | 10 | public ClientInfoMiddleware(RequestDelegate next, ILogger logger) 11 | { 12 | _next = next; 13 | _logger = logger; 14 | 15 | _logger.LogInformation("ClientInfoMiddleware is loaded"); 16 | } 17 | 18 | public async Task InvokeAsync(HttpContext context, IClientInfoRepository clientInfoRepository) 19 | { 20 | _logger.LogInformation("ClientInfoMiddleware is invoked"); 21 | 22 | var apiKey = context.Request.Headers["API-Key"].FirstOrDefault(); 23 | if (!string.IsNullOrEmpty(apiKey)) 24 | { 25 | var clientInfo = clientInfoRepository.GetClientInfo(apiKey); 26 | if (clientInfo != null) 27 | { 28 | _logger.LogInformation("ClientInfo found: {client}", clientInfo.Name); 29 | context.Features.Set(clientInfo); 30 | 31 | await _next(context); 32 | 33 | return; 34 | } 35 | } 36 | 37 | _logger.LogWarning("Unauthorized!"); 38 | context.Response.StatusCode = 401; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Projects/MiddlewareDemo/Middleware/ClientInfoMiddlewareExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace MiddlewareDemo.Middleware 2 | { 3 | public static class ClientInfoMiddlewareExtensions 4 | { 5 | public static IApplicationBuilder UseClientInfo(this IApplicationBuilder builder) 6 | { 7 | return builder.UseMiddleware(); 8 | } 9 | 10 | public static IHostApplicationBuilder AddClientInfo(this IHostApplicationBuilder builder) { 11 | 12 | builder.Services.AddSingleton(); 13 | 14 | return builder; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Projects/MiddlewareDemo/Middleware/MyHttpsRedirectionMiddleware.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting.Server.Features; 2 | using Microsoft.AspNetCore.Http; 3 | using Microsoft.AspNetCore.Http.Extensions; 4 | using Microsoft.Extensions.Configuration; 5 | 6 | namespace MyHttpsRedirection 7 | { 8 | public class MyHttpsRedirectionMiddleware 9 | { 10 | private readonly RequestDelegate _next; 11 | private readonly IConfiguration _configuration; 12 | 13 | public MyHttpsRedirectionMiddleware(RequestDelegate next, IConfiguration configuration) 14 | { 15 | _next = next; 16 | _configuration = configuration; 17 | } 18 | 19 | public async Task Invoke(HttpContext context) 20 | { 21 | if (context.Request.IsHttps) 22 | { 23 | await _next(context); 24 | } 25 | else 26 | { 27 | var httpsPort = _configuration["HTTPS_PORT"]; 28 | 29 | if (string.IsNullOrEmpty(httpsPort)) 30 | { 31 | httpsPort = "443"; 32 | } 33 | 34 | var httpsUrl = UriHelper.BuildAbsolute("https", 35 | httpsPort == "443" ? new HostString(context.Request.Host.Host) : new HostString(context.Request.Host.Host, int.Parse(httpsPort)), 36 | context.Request.PathBase, 37 | context.Request.Path, 38 | context.Request.QueryString); 39 | 40 | // context.Response.Redirect(httpsUrl); 41 | 42 | context.Response.StatusCode = StatusCodes.Status307TemporaryRedirect; 43 | context.Response.Headers.TryAdd("Location", httpsUrl); 44 | } 45 | } 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Projects/MiddlewareDemo/Middleware/MyHttpsRedirectionMiddlewareExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace MyHttpsRedirection 9 | { 10 | public static class MyHttpsRedirectionMiddlewareExtensions 11 | { 12 | public static IApplicationBuilder UseMyHttpsRedirection(this IApplicationBuilder builder) 13 | { 14 | return builder.UseMiddleware(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Projects/MiddlewareDemo/MiddlewareDemo.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Projects/MiddlewareDemo/MiddlewareDemo.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.11.35312.102 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MiddlewareDemo", "MiddlewareDemo.csproj", "{7385F3A6-16C8-4B3E-B211-80A72E27A0A9}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {7385F3A6-16C8-4B3E-B211-80A72E27A0A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {7385F3A6-16C8-4B3E-B211-80A72E27A0A9}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {7385F3A6-16C8-4B3E-B211-80A72E27A0A9}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {7385F3A6-16C8-4B3E-B211-80A72E27A0A9}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {4568DA15-9947-41BC-A6D0-54B02B258477} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /Projects/MiddlewareDemo/Models/ClientInfo.cs: -------------------------------------------------------------------------------- 1 | namespace MiddlewareDemo.Models 2 | { 3 | public class ClientInfo 4 | { 5 | public int Id { get; set; } 6 | public string Name { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Projects/MiddlewareDemo/Program.cs: -------------------------------------------------------------------------------- 1 | namespace MiddlewareDemo 2 | { 3 | public class Program 4 | { 5 | public static void Main(string[] args) 6 | { 7 | var builder = WebApplication.CreateBuilder(args); 8 | 9 | // Add services to the container. 10 | builder.Services.AddControllersWithViews(); 11 | 12 | builder.AddClientInfo(); 13 | 14 | var app = builder.Build(); 15 | 16 | // Configure the HTTP request pipeline. 17 | if (!app.Environment.IsDevelopment()) 18 | { 19 | app.UseExceptionHandler("/Home/Error"); 20 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. 21 | app.UseHsts(); 22 | } 23 | 24 | app.UseHttpsRedirection(); 25 | 26 | app.UseClientInfo(); 27 | 28 | app.UseStaticFiles(); 29 | 30 | app.UseRouting(); 31 | 32 | app.UseAuthorization(); 33 | 34 | app.MapControllerRoute( 35 | name: "default", 36 | pattern: "{controller=Home}/{action=Index}/{id?}"); 37 | 38 | app.Run(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Projects/MiddlewareDemo/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:60273", 8 | "sslPort": 44384 9 | } 10 | }, 11 | "profiles": { 12 | "http": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "applicationUrl": "http://localhost:5184", 17 | "environmentVariables": { 18 | "ASPNETCORE_ENVIRONMENT": "Development" 19 | } 20 | }, 21 | "https": { 22 | "commandName": "Project", 23 | "dotnetRunMessages": true, 24 | "launchBrowser": true, 25 | "applicationUrl": "https://localhost:7130;http://localhost:5184", 26 | "environmentVariables": { 27 | "ASPNETCORE_ENVIRONMENT": "Development" 28 | } 29 | }, 30 | "IIS Express": { 31 | "commandName": "IISExpress", 32 | "launchBrowser": true, 33 | "environmentVariables": { 34 | "ASPNETCORE_ENVIRONMENT": "Development" 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Projects/MiddlewareDemo/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Projects/MiddlewareDemo/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/MyOidcServer.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.12.35527.113 d17.12 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OidcWebClient", "OidcWebClient\OidcWebClient.csproj", "{E8C9F986-FCA6-4D97-A8F2-590F4B6181B8}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OidcServer", "OidcServer\OidcServer.csproj", "{20FEF335-800C-4D1F-A785-FDE43931986E}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {E8C9F986-FCA6-4D97-A8F2-590F4B6181B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {E8C9F986-FCA6-4D97-A8F2-590F4B6181B8}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {E8C9F986-FCA6-4D97-A8F2-590F4B6181B8}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {E8C9F986-FCA6-4D97-A8F2-590F4B6181B8}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {20FEF335-800C-4D1F-A785-FDE43931986E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {20FEF335-800C-4D1F-A785-FDE43931986E}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {20FEF335-800C-4D1F-A785-FDE43931986E}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {20FEF335-800C-4D1F-A785-FDE43931986E}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/MyOidcServer.slnLaunch.user: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Name": "New Profile", 4 | "Projects": [ 5 | { 6 | "Path": "OidcWebClient\\OidcWebClient.csproj", 7 | "Action": "Start" 8 | }, 9 | { 10 | "Path": "OidcServer\\OidcServer.csproj", 11 | "Action": "Start" 12 | } 13 | ] 14 | } 15 | ] -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using OidcServer.Models; 3 | using System.Diagnostics; 4 | 5 | namespace OidcServer.Controllers 6 | { 7 | public class HomeController : Controller 8 | { 9 | private readonly ILogger _logger; 10 | 11 | public HomeController(ILogger logger) 12 | { 13 | _logger = logger; 14 | } 15 | 16 | public IActionResult Index() 17 | { 18 | return View(); 19 | } 20 | 21 | public IActionResult Privacy() 22 | { 23 | return View(); 24 | } 25 | 26 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] 27 | public IActionResult Error() 28 | { 29 | return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Helpers/JwkLoader.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.IdentityModel.Tokens; 2 | 3 | namespace OidcServer.Helpers 4 | { 5 | public class JwkLoader 6 | { 7 | private static readonly string DefaultFile = Path.Combine("OidcDiscovery", "default-jwk.json"); 8 | private static JsonWebKey? defaultJwk = null; 9 | private static SpinLock spinLock = new SpinLock(); 10 | 11 | public static JsonWebKey LoadFromFile(string file) 12 | { 13 | var fi = new FileInfo(file); 14 | if (fi.Exists) 15 | { 16 | using var reader = fi.OpenText(); 17 | var json = reader.ReadToEnd(); 18 | 19 | return new JsonWebKey(json); 20 | } 21 | else 22 | { 23 | throw new FileNotFoundException(file); 24 | } 25 | } 26 | 27 | public static JsonWebKey LoadFromDefault() 28 | { 29 | bool lockTaken = false; 30 | 31 | spinLock.Enter(ref lockTaken); 32 | if (lockTaken) 33 | { 34 | defaultJwk ??= LoadFromFile(DefaultFile); 35 | spinLock.Exit(); 36 | } 37 | else 38 | { 39 | throw new InvalidOperationException(); // this will never happen I hope 40 | } 41 | 42 | return defaultJwk; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Helpers/JwtGenerator.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.IdentityModel.Tokens; 2 | using System.IdentityModel.Tokens.Jwt; 3 | using System.Security.Claims; 4 | 5 | namespace OidcServer.Helpers 6 | { 7 | public class JwtGenerator 8 | { 9 | public static string GenerateJWTToken(int expirySeconds, string issuer, string audience, string nonce, IEnumerable claims, JsonWebKey jsonWebKey) 10 | { 11 | var signingCredentials = new SigningCredentials(jsonWebKey, SecurityAlgorithms.RsaSha256); 12 | 13 | var additionalClaims = new Dictionary 14 | { 15 | { JwtRegisteredClaimNames.Nonce, nonce } 16 | }; 17 | 18 | var jwtHeader = new JwtHeader(signingCredentials); 19 | var jwtPayload = new JwtPayload(issuer, audience, claims, additionalClaims, null, DateTime.UtcNow.AddSeconds(expirySeconds), DateTime.UtcNow); 20 | 21 | var token = new JwtSecurityToken( 22 | jwtHeader, jwtPayload 23 | ); 24 | 25 | return new JwtSecurityTokenHandler().WriteToken(token); 26 | } 27 | 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Models/AuthenticationRequestModel.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | 3 | namespace OidcServer.Models 4 | { 5 | public class AuthenticationRequestModel 6 | { 7 | [BindProperty(Name = "client_id", SupportsGet = true)] 8 | public string ClientId { get; set; } = string.Empty; 9 | [BindProperty(Name = "redirect_uri", SupportsGet = true)] 10 | public string RedirectUri { get; set; } = string.Empty; 11 | [BindProperty(Name = "response_type", SupportsGet = true)] 12 | public string ResponseType { get; set; } = string.Empty; 13 | [BindProperty(Name = "scope", SupportsGet = true)] 14 | public string Scope { get; set; } = string.Empty; 15 | [BindProperty(Name = "code_challenge", SupportsGet = true)] 16 | public string CodeChallenge { get; set; } = string.Empty; 17 | [BindProperty(Name = "code_challenge_method", SupportsGet = true)] 18 | public string CodeChallengeMethod { get; set; } = string.Empty; 19 | [BindProperty(Name = "response_mode", SupportsGet = true)] 20 | public string ResponseMode { get; set; } = string.Empty; 21 | [BindProperty(Name = "nonce", SupportsGet = true)] 22 | public string Nonce { get; set; } = string.Empty; 23 | [BindProperty(Name = "state", SupportsGet = true)] 24 | public string State { get; set; } = string.Empty; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Models/AuthenticationResponseModel.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace OidcServer.Models 4 | { 5 | public class AuthenticationResponseModel : RefreshResponseModel 6 | { 7 | [JsonPropertyName("id_token")] 8 | public required string IdToken { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Models/CodeFlowResponseModel.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace OidcServer.Models 4 | { 5 | public class CodeFlowResponseModel 6 | { 7 | [JsonPropertyName("code")] 8 | public required string Code { get; set; } 9 | [JsonPropertyName("state")] 10 | public required string State { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Models/CodeFlowResponseViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace OidcServer.Models 4 | { 5 | public class CodeFlowResponseViewModel : CodeFlowResponseModel 6 | { 7 | [JsonPropertyName("redirect_uri")] 8 | public required string RedirectUri { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Models/CodeItem.cs: -------------------------------------------------------------------------------- 1 | namespace OidcServer.Models 2 | { 3 | public class CodeItem 4 | { 5 | public required AuthenticationRequestModel AuthenticationRequest { get; set; } 6 | public required string User { get; set; } 7 | public required string[] Scopes { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Models/ErrorViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace OidcServer.Models 2 | { 3 | public class ErrorViewModel 4 | { 5 | public string? RequestId { get; set; } 6 | 7 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Models/RefreshResponseModel.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace OidcServer.Models 4 | { 5 | public class RefreshResponseModel 6 | { 7 | [JsonPropertyName("access_token")] 8 | public required string AccessToken { get; set; } 9 | [JsonPropertyName("refresh_token")] 10 | public required string RefreshToken { get; set; } 11 | [JsonPropertyName("token_type")] 12 | public required string TokenType { get; set; } 13 | [JsonPropertyName("state")] 14 | public string? State { get; set; } 15 | [JsonPropertyName("expires_in")] 16 | public int? ExpiresIn { get; set; } 17 | } 18 | } -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Models/User.cs: -------------------------------------------------------------------------------- 1 | namespace OidcServer.Models 2 | { 3 | public class User 4 | { 5 | public string Name { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/OidcDiscovery/default-jwk.json: -------------------------------------------------------------------------------- 1 | { 2 | "p": "yGTzvbc_NotIdIfZywZqp8NNkNtGj-AGW0S1q9lUqWQ-i4wX0uR5HHIUcDLH1vmgRrhltPqUVZA4B56iR7BzKgCj1YG-Kb4RBco3Geuvd8yVZzIbvuL2LonNVroZnJYKRt1VBodpRuRe-pejjtk81ofD-HhERqg7JEA3TFogcS8", 3 | "kty": "RSA", 4 | "q": "uM0rTzjtuQDKuR2Xp6QlV8gU8OmpzKHHcD7uIEu2y6A1wugHX_SrlrTRGScSPFJ_2uvFw9BhdWHmt_bD-LM-WOW695z-r933T_KyqA7RpSpYmn_VfDuWKEzecMHx3QEfsGor5Na2BFdaboUuq_H6Gb3gAzAN9inV8g-jULRRnQs", 5 | "d": "BW81cg5gjczh_uXVfKMOrTWgqhPJVVCrVTJ2g2kBs9ffZzpxOo7UVWrE1AecrpimhGPCSrI0Ti5erFHYsjlcn43mUGGWeEf1BNAZ6aI3wYcezQHGIq19ZHNsaZEN5hdzcCFRdQY1hZGOAdsMaW-8ZmsTISa094kyQovlOlU4y-8PLyEtM1_vv7_MO4p6z_29Lol9-2pB9_91KnQlHN-WLFLxieXMgS3HQ6Aj83BaRms4PI903UjFiaQGKH014DLxUttd6bqO1-ciarGtqpHHFI8YVXpyOpusTfbmHC_h5ZL554MO3ewyFp2d6yhk3_RLzHkuGpF4gzhDDk-XUZUH6Q", 6 | "e": "AQAB", 7 | "use": "sig", 8 | "qi": "PjAzBS5FDD4qc5OeWH2e55nBJ9gxW1u_f4xeGh6mlK7-CjwEjtDgeI4SFMADEhckVvng62vHjsOB8AgpZZ-_gzSENLc1-NASO3lM1YeKnii3y8Bn5CoPWnOCeIf_8OowzG6iBxpmqiTK8Elhz4sX3bn9ZMzauOp_c_bjXdsyOVw", 9 | "dp": "Fjbisjg7IK_GA2z_3rrCXgCPe6xjIRXjfoCaZwd7lB-Rs2R_S5iaOGYJD_sBHjqj4tMUK0DP6sBHBck3Eh1kVtalUsjELNpuBqdI_m2bEPuz4DG0069TPQt3oNKWfj4_u2VTxJqEOCCeysa-kdpRHTMFrWifoPmLPNSFjMg86m8", 10 | "alg": "RS256", 11 | "dq": "PTN1TF9GGyav_G5YcyRhWZjhlodLvIE3U20D354zg2wjYdEF4DlfOiHXvcS6vU91GENM03SHUiCCEBqg_BQgacBrEuXjUsrnxIpTsGR3-YL0pPYA9YumRuJuKFmSh-Z_YCVJNBgHX5iuUju5ISiZ8zx2m5emiAeC2w9ivq9499E", 12 | "n": "kKkp7oNJbb6t1SRu5GXUWx5ZZH32jF-6vC74FZP52XuokBnVrhHE9vbgDpphji0JDOwbSkstlWLezEWQikzTYjZDndUKYmjykAaFsP0Ga5thjAR8aFuCl-V4gyr-Ch9aa2LyT2gJiwemg_UBgZM4Kl6TQofPkgFvO341eD-LqXqnevH1FHqfPdWetVJ_m9rHNzsMXZty_lAZfYmMnVGmFj9DGmv6Ym1TAxC_lca0jB_92WA77_B4otdllv9ZSIkeBJixyHucGdi-vYwBOXVuT_SL1z-aDyYeBwsIezZS2m0VRsWV_2cKpExJYAZuZ4Pbw48J-wukqjgBKNMWoK2wBQ" 13 | } -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/OidcDiscovery/jwks.json: -------------------------------------------------------------------------------- 1 | { 2 | "jwks": [ 3 | { 4 | "kty": "RSA", 5 | "e": "AQAB", 6 | "use": "sig", 7 | "alg": "RS256", 8 | "n": "kKkp7oNJbb6t1SRu5GXUWx5ZZH32jF-6vC74FZP52XuokBnVrhHE9vbgDpphji0JDOwbSkstlWLezEWQikzTYjZDndUKYmjykAaFsP0Ga5thjAR8aFuCl-V4gyr-Ch9aa2LyT2gJiwemg_UBgZM4Kl6TQofPkgFvO341eD-LqXqnevH1FHqfPdWetVJ_m9rHNzsMXZty_lAZfYmMnVGmFj9DGmv6Ym1TAxC_lca0jB_92WA77_B4otdllv9ZSIkeBJixyHucGdi-vYwBOXVuT_SL1z-aDyYeBwsIezZS2m0VRsWV_2cKpExJYAZuZ4Pbw48J-wukqjgBKNMWoK2wBQ" 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/OidcDiscovery/openid-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "issuer": "https://localhost:7082/", 3 | "authorization_endpoint": "https://localhost:7082/authorize", 4 | "token_endpoint": "https://localhost:7082/oauth/token", 5 | "userinfo_endpoint": "https://localhost:7082/userinfo", 6 | "jwks_uri": "https://localhost:7082/.well-known/jwks.json", 7 | "scopes_supported": [ 8 | "openid", 9 | "profile", 10 | "email", 11 | "email_verified" 12 | ] 13 | } -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/OidcServer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/OidcServer.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | https 5 | MvcControllerEmptyScaffolder 6 | root/Common/MVC/Controller 7 | RazorViewEmptyScaffolder 8 | root/Common/MVC/View 9 | 10 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Program.cs: -------------------------------------------------------------------------------- 1 | using OidcServer.Repositories; 2 | 3 | namespace OidcServer 4 | { 5 | public class Program 6 | { 7 | public static void Main(string[] args) 8 | { 9 | var builder = WebApplication.CreateBuilder(args); 10 | 11 | // Add services to the container. 12 | builder.Services.AddControllersWithViews(); 13 | 14 | builder.Services.AddSingleton(); 15 | builder.Services.AddSingleton(); 16 | 17 | var app = builder.Build(); 18 | 19 | // Configure the HTTP request pipeline. 20 | if (!app.Environment.IsDevelopment()) 21 | { 22 | app.UseExceptionHandler("/Home/Error"); 23 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. 24 | app.UseHsts(); 25 | } 26 | 27 | app.UseHttpsRedirection(); 28 | app.UseStaticFiles(); 29 | 30 | app.UseRouting(); 31 | 32 | app.UseAuthorization(); 33 | 34 | app.MapGet("/.well-known/openid-configuration", 35 | () => Results.File(Path.Combine(builder.Environment.ContentRootPath, "OidcDiscovery", "openid-configuration.json"), contentType: "application/json") 36 | ); 37 | 38 | app.MapGet("/.well-known/jwks.json", 39 | () => Results.File(Path.Combine(builder.Environment.ContentRootPath, "OidcDiscovery", "jwks.json"), contentType: "application/json") 40 | ); 41 | 42 | app.MapControllerRoute( 43 | name: "default", 44 | pattern: "{controller=Home}/{action=Index}/{id?}"); 45 | 46 | app.Run(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:55348", 8 | "sslPort": 44387 9 | } 10 | }, 11 | "profiles": { 12 | "http": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "applicationUrl": "http://localhost:5204", 17 | "environmentVariables": { 18 | "ASPNETCORE_ENVIRONMENT": "Development" 19 | } 20 | }, 21 | "https": { 22 | "commandName": "Project", 23 | "dotnetRunMessages": true, 24 | "launchBrowser": true, 25 | "applicationUrl": "https://localhost:7082;http://localhost:5204", 26 | "environmentVariables": { 27 | "ASPNETCORE_ENVIRONMENT": "Development" 28 | } 29 | }, 30 | "IIS Express": { 31 | "commandName": "IISExpress", 32 | "launchBrowser": true, 33 | "environmentVariables": { 34 | "ASPNETCORE_ENVIRONMENT": "Development" 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Repositories/CodeItemRepository.cs: -------------------------------------------------------------------------------- 1 | using OidcServer.Models; 2 | 3 | namespace OidcServer.Repositories 4 | { 5 | public class CodeItemRepository : ICodeItemRepository 6 | { 7 | private readonly Dictionary items = []; 8 | 9 | public void Add(string code, CodeItem codeItem) 10 | { 11 | items[code] = codeItem; 12 | } 13 | 14 | public void Delete(string code) 15 | { 16 | items.Remove(code); 17 | } 18 | 19 | public CodeItem? FindByCode(string code) 20 | { 21 | return items.TryGetValue(code, out var codeItem) ? codeItem : null; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Repositories/ICodeItemRepository.cs: -------------------------------------------------------------------------------- 1 | using OidcServer.Models; 2 | 3 | namespace OidcServer.Repositories 4 | { 5 | public interface ICodeItemRepository 6 | { 7 | CodeItem? FindByCode(string code); 8 | void Add(string code, CodeItem codeItem); 9 | void Delete(string code); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Repositories/IUserRepository.cs: -------------------------------------------------------------------------------- 1 | using OidcServer.Models; 2 | 3 | namespace OidcServer.Repositories 4 | { 5 | public interface IUserRepository 6 | { 7 | User? FindByUsername(string username); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Repositories/InMemoryUserRepository.cs: -------------------------------------------------------------------------------- 1 | using OidcServer.Models; 2 | 3 | namespace OidcServer.Repositories 4 | { 5 | public class InMemoryUserRepository : IUserRepository 6 | { 7 | private readonly List _users = 8 | [ 9 | new() { Name = "alice" }, 10 | new() { Name = "bob" }, 11 | new() { Name = "nam" } 12 | ]; 13 | 14 | public User? FindByUsername(string username) 15 | { 16 | return _users.FirstOrDefault(x => x.Name.Equals(username, StringComparison.OrdinalIgnoreCase)); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Views/Authorize/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model AuthenticationRequestModel 2 | @{ 3 | int i; 4 | } 5 |
6 |

Choose one of the following accounts to continue authorizing

7 |
8 |
9 |
10 |
11 |
User1
12 |
13 | 14 | @{ 15 | i = 1; 16 | } 17 | @foreach (var scope in Model.Scope.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)) 18 | { 19 |
20 | 21 | 24 |
25 | 26 | i++; 27 | } 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
42 |
43 |
44 |
45 |
46 |
47 | Cancel authorizing 48 |
49 |
50 |
51 |
-------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Views/Authorize/SubmitForm.cshtml: -------------------------------------------------------------------------------- 1 | @model CodeFlowResponseViewModel 2 | @{ 3 | Layout = null; 4 | } 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 |
14 | 15 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Views/Authorize/UserNotFound.cshtml: -------------------------------------------------------------------------------- 1 | @* 2 | For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 3 | *@ 4 | @{ 5 | ViewData["Title"] = "User Not Found"; 6 | } 7 | 8 |

User Not Found

9 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Home Page"; 3 | } 4 | 5 |
6 |

OIDC Server

7 |
8 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Views/Home/Privacy.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Privacy Policy"; 3 | } 4 |

@ViewData["Title"]

5 | 6 |

Use this page to detail your site's privacy policy.

7 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @model ErrorViewModel 2 | @{ 3 | ViewData["Title"] = "Error"; 4 | } 5 | 6 |

Error.

7 |

An error occurred while processing your request.

8 | 9 | @if (Model.ShowRequestId) 10 | { 11 |

12 | Request ID: @Model.RequestId 13 |

14 | } 15 | 16 |

Development Mode

17 |

18 | Swapping to Development environment will display more detailed information about the error that occurred. 19 |

20 |

21 | The Development environment shouldn't be enabled for deployed applications. 22 | It can result in displaying sensitive information from exceptions to end users. 23 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development 24 | and restarting the app. 25 |

26 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewData["Title"] - OidcServer 7 | 8 | 9 | 10 | 11 | 12 |
13 | 32 |
33 |
34 |
35 | @RenderBody() 36 |
37 |
38 | 39 |
40 |
41 | © 2024 - OidcServer - Privacy 42 |
43 |
44 | 45 | 46 | 47 | @await RenderSectionAsync("Scripts", required: false) 48 | 49 | 50 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Views/Shared/_Layout.cshtml.css: -------------------------------------------------------------------------------- 1 | /* Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | for details on configuring this project to bundle and minify static web assets. */ 3 | 4 | a.navbar-brand { 5 | white-space: normal; 6 | text-align: center; 7 | word-break: break-all; 8 | } 9 | 10 | a { 11 | color: #0077cc; 12 | } 13 | 14 | .btn-primary { 15 | color: #fff; 16 | background-color: #1b6ec2; 17 | border-color: #1861ac; 18 | } 19 | 20 | .nav-pills .nav-link.active, .nav-pills .show > .nav-link { 21 | color: #fff; 22 | background-color: #1b6ec2; 23 | border-color: #1861ac; 24 | } 25 | 26 | .border-top { 27 | border-top: 1px solid #e5e5e5; 28 | } 29 | .border-bottom { 30 | border-bottom: 1px solid #e5e5e5; 31 | } 32 | 33 | .box-shadow { 34 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05); 35 | } 36 | 37 | button.accept-policy { 38 | font-size: 1rem; 39 | line-height: inherit; 40 | } 41 | 42 | .footer { 43 | position: absolute; 44 | bottom: 0; 45 | width: 100%; 46 | white-space: nowrap; 47 | line-height: 60px; 48 | } 49 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Views/Shared/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using OidcServer 2 | @using OidcServer.Models 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-size: 14px; 3 | } 4 | 5 | @media (min-width: 768px) { 6 | html { 7 | font-size: 16px; 8 | } 9 | } 10 | 11 | .btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus { 12 | box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb; 13 | } 14 | 15 | html { 16 | position: relative; 17 | min-height: 100%; 18 | } 19 | 20 | body { 21 | margin-bottom: 60px; 22 | } -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daohainam/lets-learn-aspnet/ee9bcdf96c487cd2a270c660f5ff468f776241a0/Projects/MyOidcServer/OidcServer/wwwroot/favicon.ico -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/wwwroot/js/site.js: -------------------------------------------------------------------------------- 1 | // Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | // for details on configuring this project to bundle and minify static web assets. 3 | 4 | // Write your JavaScript code. 5 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/wwwroot/lib/bootstrap/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2021 Twitter, Inc. 4 | Copyright (c) 2011-2021 The Bootstrap Authors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) .NET Foundation and Contributors 4 | 5 | All rights reserved. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/wwwroot/lib/jquery-validation/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright Jörn Zaefferer 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcServer/wwwroot/lib/jquery/LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Copyright OpenJS Foundation and other contributors, https://openjsf.org/ 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcWebClient/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using Microsoft.AspNetCore.Mvc; 3 | using OidcWebClient.Models; 4 | 5 | namespace OidcWebClient.Controllers 6 | { 7 | public class HomeController : Controller 8 | { 9 | private readonly ILogger _logger; 10 | 11 | public HomeController(ILogger logger) 12 | { 13 | _logger = logger; 14 | } 15 | 16 | public IActionResult Index() 17 | { 18 | return View(); 19 | } 20 | 21 | public IActionResult Privacy() 22 | { 23 | return View(); 24 | } 25 | 26 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] 27 | public IActionResult Error() 28 | { 29 | return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcWebClient/Controllers/ProfileController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | using Microsoft.AspNetCore.Mvc; 3 | 4 | namespace OidcWebClient.Controllers 5 | { 6 | public class ProfileController : Controller 7 | { 8 | [Authorize] 9 | public IActionResult Index() 10 | { 11 | return View(); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcWebClient/Models/ErrorViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace OidcWebClient.Models 2 | { 3 | public class ErrorViewModel 4 | { 5 | public string? RequestId { get; set; } 6 | 7 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcWebClient/OidcWebClient.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcWebClient/OidcWebClient.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | https 5 | MvcControllerEmptyScaffolder 6 | root/Common/MVC/Controller 7 | RazorViewEmptyScaffolder 8 | root/Common/MVC/View 9 | 10 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcWebClient/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authentication.Cookies; 2 | using Microsoft.AspNetCore.Authentication.OpenIdConnect; 3 | using Microsoft.IdentityModel.Logging; 4 | using Microsoft.IdentityModel.Protocols.OpenIdConnect; 5 | using Microsoft.IdentityModel.Tokens; 6 | using System.IdentityModel.Tokens.Jwt; 7 | 8 | namespace OidcWebClient 9 | { 10 | public class Program 11 | { 12 | public static void Main(string[] args) 13 | { 14 | var builder = WebApplication.CreateBuilder(args); 15 | 16 | if (builder.Environment.IsDevelopment()) 17 | { 18 | IdentityModelEventSource.ShowPII = true; 19 | } 20 | 21 | // Add services to the container. 22 | builder.Services.AddControllersWithViews(); 23 | 24 | // Add OpenIdConnect authentication 25 | builder.Services.AddAuthentication(options => 26 | { 27 | options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; 28 | options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; 29 | options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; 30 | }) 31 | .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme) 32 | .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options => 33 | { 34 | options.Authority = builder.Configuration["Oidc:Authority"]; 35 | options.ClientId = builder.Configuration["Oidc:ClientId"]; 36 | options.ClientSecret = builder.Configuration["Oidc:ClientSecret"]; 37 | options.ResponseType = OpenIdConnectResponseType.Code; 38 | options.SaveTokens = true; 39 | 40 | options.TokenValidationParameters.ValidateIssuerSigningKey = false; 41 | options.TokenValidationParameters.SignatureValidator = delegate (string token, TokenValidationParameters validationParameters) { return new Microsoft.IdentityModel.JsonWebTokens.JsonWebToken(token); }; 42 | }); 43 | 44 | var app = builder.Build(); 45 | 46 | // Configure the HTTP request pipeline. 47 | if (!app.Environment.IsDevelopment()) 48 | { 49 | app.UseExceptionHandler("/Home/Error"); 50 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. 51 | app.UseHsts(); 52 | } 53 | 54 | app.UseHttpsRedirection(); 55 | app.UseStaticFiles(); 56 | 57 | app.UseRouting(); 58 | 59 | app.UseAuthentication(); 60 | app.UseAuthorization(); 61 | 62 | app.MapControllerRoute( 63 | name: "default", 64 | pattern: "{controller=Home}/{action=Index}/{id?}"); 65 | 66 | app.Run(); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcWebClient/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:10342", 8 | "sslPort": 44348 9 | } 10 | }, 11 | "profiles": { 12 | "http": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "applicationUrl": "http://localhost:5202", 17 | "environmentVariables": { 18 | "ASPNETCORE_ENVIRONMENT": "Development" 19 | } 20 | }, 21 | "https": { 22 | "commandName": "Project", 23 | "dotnetRunMessages": true, 24 | "launchBrowser": true, 25 | "applicationUrl": "https://localhost:7095;http://localhost:5202", 26 | "environmentVariables": { 27 | "ASPNETCORE_ENVIRONMENT": "Development" 28 | } 29 | }, 30 | "IIS Express": { 31 | "commandName": "IISExpress", 32 | "launchBrowser": true, 33 | "environmentVariables": { 34 | "ASPNETCORE_ENVIRONMENT": "Development" 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcWebClient/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Home Page"; 3 | } 4 | 5 |
6 |

Web Client

7 |

8 | Profile 9 |

10 | 11 |
12 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcWebClient/Views/Home/Privacy.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Privacy Policy"; 3 | } 4 |

@ViewData["Title"]

5 | 6 |

Use this page to detail your site's privacy policy.

7 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcWebClient/Views/Profile/Index.cshtml: -------------------------------------------------------------------------------- 1 | @* 2 | For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 3 | *@ 4 | @{ 5 | } 6 | 7 |

Profile

8 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcWebClient/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @model ErrorViewModel 2 | @{ 3 | ViewData["Title"] = "Error"; 4 | } 5 | 6 |

Error.

7 |

An error occurred while processing your request.

8 | 9 | @if (Model.ShowRequestId) 10 | { 11 |

12 | Request ID: @Model.RequestId 13 |

14 | } 15 | 16 |

Development Mode

17 |

18 | Swapping to Development environment will display more detailed information about the error that occurred. 19 |

20 |

21 | The Development environment shouldn't be enabled for deployed applications. 22 | It can result in displaying sensitive information from exceptions to end users. 23 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development 24 | and restarting the app. 25 |

26 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcWebClient/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewData["Title"] - OidcWebClient 7 | 8 | 9 | 10 | 11 | 12 |
13 | 32 |
33 |
34 |
35 | @RenderBody() 36 |
37 |
38 | 39 |
40 |
41 | © 2024 - OidcWebClient - Privacy 42 |
43 |
44 | 45 | 46 | 47 | @await RenderSectionAsync("Scripts", required: false) 48 | 49 | 50 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcWebClient/Views/Shared/_Layout.cshtml.css: -------------------------------------------------------------------------------- 1 | /* Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | for details on configuring this project to bundle and minify static web assets. */ 3 | 4 | a.navbar-brand { 5 | white-space: normal; 6 | text-align: center; 7 | word-break: break-all; 8 | } 9 | 10 | a { 11 | color: #0077cc; 12 | } 13 | 14 | .btn-primary { 15 | color: #fff; 16 | background-color: #1b6ec2; 17 | border-color: #1861ac; 18 | } 19 | 20 | .nav-pills .nav-link.active, .nav-pills .show > .nav-link { 21 | color: #fff; 22 | background-color: #1b6ec2; 23 | border-color: #1861ac; 24 | } 25 | 26 | .border-top { 27 | border-top: 1px solid #e5e5e5; 28 | } 29 | .border-bottom { 30 | border-bottom: 1px solid #e5e5e5; 31 | } 32 | 33 | .box-shadow { 34 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05); 35 | } 36 | 37 | button.accept-policy { 38 | font-size: 1rem; 39 | line-height: inherit; 40 | } 41 | 42 | .footer { 43 | position: absolute; 44 | bottom: 0; 45 | width: 100%; 46 | white-space: nowrap; 47 | line-height: 60px; 48 | } 49 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcWebClient/Views/Shared/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcWebClient/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using OidcWebClient 2 | @using OidcWebClient.Models 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcWebClient/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcWebClient/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcWebClient/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*", 9 | "Oidc": { 10 | "Authority": "https://localhost:7082/", 11 | "ClientId": "OidcWebClient", 12 | "ClientSecret": "secret" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcWebClient/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-size: 14px; 3 | } 4 | 5 | @media (min-width: 768px) { 6 | html { 7 | font-size: 16px; 8 | } 9 | } 10 | 11 | .btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus { 12 | box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb; 13 | } 14 | 15 | html { 16 | position: relative; 17 | min-height: 100%; 18 | } 19 | 20 | body { 21 | margin-bottom: 60px; 22 | } -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcWebClient/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daohainam/lets-learn-aspnet/ee9bcdf96c487cd2a270c660f5ff468f776241a0/Projects/MyOidcServer/OidcWebClient/wwwroot/favicon.ico -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcWebClient/wwwroot/js/site.js: -------------------------------------------------------------------------------- 1 | // Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | // for details on configuring this project to bundle and minify static web assets. 3 | 4 | // Write your JavaScript code. 5 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcWebClient/wwwroot/lib/bootstrap/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2021 Twitter, Inc. 4 | Copyright (c) 2011-2021 The Bootstrap Authors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcWebClient/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) .NET Foundation and Contributors 4 | 5 | All rights reserved. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcWebClient/wwwroot/lib/jquery-validation/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright Jörn Zaefferer 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Projects/MyOidcServer/OidcWebClient/wwwroot/lib/jquery/LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Copyright OpenJS Foundation and other contributors, https://openjsf.org/ 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Projects/MySession/MySession.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.11.35312.102 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MySession", "MySession\MySession.csproj", "{B25B4C7E-420F-4D09-9B16-169FED4848D8}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MySessionIntegrationTest", "MySessionIntegrationTest\MySessionIntegrationTest.csproj", "{4D122BA2-33BB-4B2D-986F-5063E844CE2A}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {B25B4C7E-420F-4D09-9B16-169FED4848D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {B25B4C7E-420F-4D09-9B16-169FED4848D8}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {B25B4C7E-420F-4D09-9B16-169FED4848D8}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {B25B4C7E-420F-4D09-9B16-169FED4848D8}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {4D122BA2-33BB-4B2D-986F-5063E844CE2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {4D122BA2-33BB-4B2D-986F-5063E844CE2A}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {4D122BA2-33BB-4B2D-986F-5063E844CE2A}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {4D122BA2-33BB-4B2D-986F-5063E844CE2A}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {BFCF46EE-ACAF-44B9-B18B-A37B63124251} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace MySession.Controllers; 3 | 4 | public class HomeController : Controller 5 | { 6 | private readonly ILogger _logger; 7 | 8 | public HomeController(ILogger logger) 9 | { 10 | _logger = logger; 11 | } 12 | 13 | public async Task IndexAsync() 14 | { 15 | var session = HttpContext.GetSession(); 16 | 17 | session.SetString("Name", "Tom"); 18 | await session.CommitAsync(); 19 | 20 | return View(); 21 | } 22 | 23 | public async Task PrivacyAsync() 24 | { 25 | var session = HttpContext.GetSession(); 26 | await session.LoadAsync(); 27 | var name = session.GetString("Name"); 28 | 29 | return View("Privacy", name); 30 | } 31 | 32 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] 33 | public IActionResult Error() 34 | { 35 | return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/Controllers/TestController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | 3 | namespace MySession.Controllers 4 | { 5 | public class TestController : Controller 6 | { 7 | public IActionResult TestGetSession() 8 | { 9 | var session = HttpContext.GetSession(); 10 | 11 | session.SetString("Name", "123456789ABC"); 12 | 13 | session = HttpContext.GetSession(); 14 | var value = session.GetString("Name"); 15 | 16 | if (value == "123456789ABC") 17 | { 18 | return Ok(); 19 | } 20 | else 21 | { 22 | return BadRequest(); 23 | } 24 | } 25 | 26 | public async Task SetSessionValueAsync(string key, string value) { 27 | var session = HttpContext.GetSession(); 28 | await session.LoadAsync(); 29 | 30 | session.SetString(key, value); 31 | 32 | await session.CommitAsync(); 33 | 34 | return Ok(); 35 | } 36 | 37 | public async Task GetSessionValueAsync(string key) 38 | { 39 | var session = HttpContext.GetSession(); 40 | await session.LoadAsync(); 41 | var value = session.GetString(key); 42 | 43 | return Ok(value); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using MySession.MySession; 2 | global using Microsoft.AspNetCore.Mvc; 3 | global using MySession.Models; 4 | global using System.Diagnostics; 5 | global using System.Text; 6 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/Models/ErrorViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace MySession.Models 2 | { 3 | public class ErrorViewModel 4 | { 5 | public string? RequestId { get; set; } 6 | 7 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/MySession.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/MySession.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | https 5 | MvcControllerEmptyScaffolder 6 | root/Common/MVC/Controller 7 | 8 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/MySession/FileMySessionStorageEngine.cs: -------------------------------------------------------------------------------- 1 |  2 | using System.Text.Json.Serialization; 3 | using System.Threading; 4 | 5 | namespace MySession.MySession 6 | { 7 | public class FileMySessionStorageEngine : IMySessionStorageEngine 8 | { 9 | private readonly string _directoryPath; 10 | 11 | public FileMySessionStorageEngine(string directoryPath) 12 | { 13 | _directoryPath = directoryPath; 14 | } 15 | 16 | public async Task CommitAsync(string id, Dictionary _store, CancellationToken cancellationToken) 17 | { 18 | string filePath = Path.Combine(_directoryPath, id); 19 | using FileStream fileStream = new FileStream(filePath, FileMode.Create); 20 | using StreamWriter streamWriter = new StreamWriter(fileStream); 21 | 22 | streamWriter.Write(System.Text.Json.JsonSerializer.Serialize(_store)); 23 | 24 | //foreach (var entry in _store) 25 | //{ 26 | // await fileStream.WriteAsync(entry.Value, 0, entry.Value.Length, cancellationToken); 27 | //} 28 | } 29 | 30 | public Dictionary Load(string id) 31 | { 32 | string filePath = Path.Combine(_directoryPath, id); 33 | if (!File.Exists(filePath)) 34 | { 35 | return []; 36 | } 37 | 38 | using FileStream fileStream = new FileStream(filePath, FileMode.Open); 39 | using StreamReader streamReader = new StreamReader(fileStream); 40 | 41 | var json = streamReader.ReadToEnd(); 42 | return System.Text.Json.JsonSerializer.Deserialize>(json) ?? []; 43 | } 44 | 45 | public async Task> LoadAsync(string id, CancellationToken cancellationToken) 46 | { 47 | string filePath = Path.Combine(_directoryPath, id); 48 | if (!File.Exists(filePath)) 49 | { 50 | return []; 51 | } 52 | 53 | using FileStream fileStream = new FileStream(filePath, FileMode.Open); 54 | using StreamReader streamReader = new StreamReader(fileStream); 55 | 56 | var json = await streamReader.ReadToEndAsync(cancellationToken); 57 | return System.Text.Json.JsonSerializer.Deserialize>(json) ?? []; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/MySession/IMySessionStorage.cs: -------------------------------------------------------------------------------- 1 | namespace MySession.MySession 2 | { 3 | public interface IMySessionStorage 4 | { 5 | ISession Create(); 6 | ISession Get(string id); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/MySession/IMySessionStorageEngine.cs: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | namespace MySession.MySession 5 | { 6 | public interface IMySessionStorageEngine 7 | { 8 | Task CommitAsync(string id, Dictionary _store, CancellationToken cancellationToken); 9 | Dictionary Load(string id); 10 | Task> LoadAsync(string id, CancellationToken cancellationToken); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/MySession/MySession.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | namespace MySession.MySession 4 | { 5 | public class MySession(string id, IMySessionStorageEngine engine) : ISession 6 | { 7 | private readonly Dictionary _store = new Dictionary(); 8 | 9 | public bool IsAvailable { 10 | get { 11 | Load(); 12 | 13 | return true; 14 | } 15 | } 16 | 17 | public string Id => id; 18 | 19 | public IEnumerable Keys => _store.Keys; 20 | 21 | public void Clear() 22 | { 23 | _store.Clear(); 24 | } 25 | 26 | public async Task CommitAsync(CancellationToken cancellationToken = default) 27 | { 28 | await engine.CommitAsync(Id, _store, cancellationToken); 29 | } 30 | 31 | public async Task LoadAsync(CancellationToken cancellationToken = default) 32 | { 33 | _store.Clear(); 34 | var loadedStore = await engine.LoadAsync(Id, cancellationToken); 35 | 36 | foreach (var pair in loadedStore) 37 | { 38 | _store[pair.Key] = pair.Value; 39 | } 40 | } 41 | 42 | public void Load() 43 | { 44 | _store.Clear(); 45 | var loadedStore = engine.Load(Id); 46 | 47 | foreach (var pair in loadedStore) 48 | { 49 | _store[pair.Key] = pair.Value; 50 | } 51 | } 52 | 53 | public void Remove(string key) 54 | { 55 | _store.Remove(key); 56 | } 57 | 58 | public void Set(string key, byte[] value) 59 | { 60 | _store[key] = value; 61 | } 62 | 63 | public bool TryGetValue(string key, [NotNullWhen(true)] out byte[]? value) 64 | { 65 | return _store.TryGetValue(key, out value); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/MySession/MySessionExtensions.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace MySession.MySession 3 | { 4 | public static class MySessionExtensions 5 | { 6 | public const string SessionIdCookieName = "MY_SESSION_ID"; 7 | 8 | public static ISession GetSession(this HttpContext context) 9 | { 10 | var sessionContainer = context.RequestServices.GetRequiredService(); 11 | if (sessionContainer.Session != null) 12 | { 13 | return sessionContainer.Session; 14 | } 15 | else 16 | { 17 | string? sessionId = context.Request.Cookies[SessionIdCookieName]; 18 | 19 | if (IsSessionIdFormatValid(sessionId)) 20 | { 21 | var session = context.RequestServices.GetRequiredService().Get(sessionId!); 22 | context.Response.Cookies.Append(SessionIdCookieName, session.Id, new CookieOptions() 23 | { 24 | HttpOnly = true, 25 | }); 26 | 27 | sessionContainer.Session = session; 28 | 29 | return session; 30 | } 31 | else 32 | { 33 | var session = context.RequestServices.GetRequiredService().Create(); 34 | context.Response.Cookies.Append(SessionIdCookieName, session.Id, new CookieOptions() 35 | { 36 | HttpOnly = true, 37 | }); 38 | 39 | sessionContainer.Session = session; 40 | 41 | return session; 42 | } 43 | } 44 | } 45 | 46 | private static bool IsSessionIdFormatValid(string? sessionId) 47 | { 48 | return !string.IsNullOrEmpty(sessionId) && Guid.TryParse(sessionId, out var _); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/MySession/MySessionRegistrationExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace MySession.MySession 2 | { 3 | public static class MySessionRegistrationExtensions 4 | { 5 | public static IServiceCollection AddMySession(this IServiceCollection services) 6 | { 7 | services.AddSingleton(services => 8 | { 9 | var path = Path.Combine(services.GetRequiredService().ContentRootPath, "sessions"); 10 | Directory.CreateDirectory(path); 11 | 12 | return new FileMySessionStorageEngine(path); 13 | }); 14 | services.AddSingleton(); 15 | services.AddScoped(); 16 | 17 | return services; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/MySession/MySessionScopedContainer.cs: -------------------------------------------------------------------------------- 1 | namespace MySession.MySession 2 | { 3 | public class MySessionScopedContainer 4 | { 5 | public MySessionScopedContainer(ILogger logger) { 6 | logger.LogInformation("MySessionScopedContainer created"); 7 | } 8 | 9 | public ISession? Session { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/MySession/MySessionStorage.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace MySession.MySession 3 | { 4 | public class MySessionStorage : IMySessionStorage 5 | { 6 | private readonly IMySessionStorageEngine engine; 7 | private readonly Dictionary sessions = new Dictionary(); 8 | 9 | public MySessionStorage(IMySessionStorageEngine engine) 10 | { 11 | this.engine = engine; 12 | } 13 | 14 | public ISession Create() 15 | { 16 | var newSession = new MySession(Guid.NewGuid().ToString("N"), engine); 17 | sessions[newSession.Id] = newSession; 18 | 19 | return newSession; 20 | } 21 | 22 | public ISession Get(string id) 23 | { 24 | if (sessions.ContainsKey(id)) 25 | { 26 | return sessions[id]; 27 | } 28 | 29 | return Create(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/Program.cs: -------------------------------------------------------------------------------- 1 | namespace MySession 2 | { 3 | public class Program 4 | { 5 | public static void Main(string[] args) 6 | { 7 | var builder = WebApplication.CreateBuilder(args); 8 | 9 | // Add services to the container. 10 | builder.Services.AddControllersWithViews(); 11 | builder.Services.AddMySession(); 12 | 13 | var app = builder.Build(); 14 | 15 | // Configure the HTTP request pipeline. 16 | if (!app.Environment.IsDevelopment()) 17 | { 18 | app.UseExceptionHandler("/Home/Error"); 19 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. 20 | app.UseHsts(); 21 | } 22 | 23 | app.UseHttpsRedirection(); 24 | app.UseStaticFiles(); 25 | 26 | app.UseRouting(); 27 | 28 | app.UseAuthorization(); 29 | 30 | app.MapControllerRoute( 31 | name: "default", 32 | pattern: "{controller=Home}/{action=Index}/{id?}"); 33 | 34 | app.Run(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:2152", 8 | "sslPort": 44363 9 | } 10 | }, 11 | "profiles": { 12 | "http": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "applicationUrl": "http://localhost:5023", 17 | "environmentVariables": { 18 | "ASPNETCORE_ENVIRONMENT": "Development" 19 | } 20 | }, 21 | "https": { 22 | "commandName": "Project", 23 | "dotnetRunMessages": true, 24 | "launchBrowser": true, 25 | "applicationUrl": "https://localhost:7285;http://localhost:5023", 26 | "environmentVariables": { 27 | "ASPNETCORE_ENVIRONMENT": "Development" 28 | } 29 | }, 30 | "IIS Express": { 31 | "commandName": "IISExpress", 32 | "launchBrowser": true, 33 | "environmentVariables": { 34 | "ASPNETCORE_ENVIRONMENT": "Development" 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Home Page"; 3 | } 4 | 5 |
6 |

Welcome

7 |

Learn about building Web apps with ASP.NET Core.

8 |
9 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/Views/Home/Privacy.cshtml: -------------------------------------------------------------------------------- 1 | @model string 2 | 3 | @{ 4 | ViewData["Title"] = Model; 5 | } 6 |

@ViewData["Title"]

7 | 8 |

(@Model)Use this page to detail your site's privacy policy.

9 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @model ErrorViewModel 2 | @{ 3 | ViewData["Title"] = "Error"; 4 | } 5 | 6 |

Error.

7 |

An error occurred while processing your request.

8 | 9 | @if (Model.ShowRequestId) 10 | { 11 |

12 | Request ID: @Model.RequestId 13 |

14 | } 15 | 16 |

Development Mode

17 |

18 | Swapping to Development environment will display more detailed information about the error that occurred. 19 |

20 |

21 | The Development environment shouldn't be enabled for deployed applications. 22 | It can result in displaying sensitive information from exceptions to end users. 23 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development 24 | and restarting the app. 25 |

26 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewData["Title"] - MySession 7 | 8 | 9 | 10 | 11 | 12 |
13 | 32 |
33 |
34 |
35 | @RenderBody() 36 |
37 |
38 | 39 |
40 |
41 | © 2024 - MySession - Privacy 42 |
43 |
44 | 45 | 46 | 47 | @await RenderSectionAsync("Scripts", required: false) 48 | 49 | 50 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/Views/Shared/_Layout.cshtml.css: -------------------------------------------------------------------------------- 1 | /* Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | for details on configuring this project to bundle and minify static web assets. */ 3 | 4 | a.navbar-brand { 5 | white-space: normal; 6 | text-align: center; 7 | word-break: break-all; 8 | } 9 | 10 | a { 11 | color: #0077cc; 12 | } 13 | 14 | .btn-primary { 15 | color: #fff; 16 | background-color: #1b6ec2; 17 | border-color: #1861ac; 18 | } 19 | 20 | .nav-pills .nav-link.active, .nav-pills .show > .nav-link { 21 | color: #fff; 22 | background-color: #1b6ec2; 23 | border-color: #1861ac; 24 | } 25 | 26 | .border-top { 27 | border-top: 1px solid #e5e5e5; 28 | } 29 | .border-bottom { 30 | border-bottom: 1px solid #e5e5e5; 31 | } 32 | 33 | .box-shadow { 34 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05); 35 | } 36 | 37 | button.accept-policy { 38 | font-size: 1rem; 39 | line-height: inherit; 40 | } 41 | 42 | .footer { 43 | position: absolute; 44 | bottom: 0; 45 | width: 100%; 46 | white-space: nowrap; 47 | line-height: 60px; 48 | } 49 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/Views/Shared/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using MySession 2 | @using MySession.Models 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-size: 14px; 3 | } 4 | 5 | @media (min-width: 768px) { 6 | html { 7 | font-size: 16px; 8 | } 9 | } 10 | 11 | .btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus { 12 | box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb; 13 | } 14 | 15 | html { 16 | position: relative; 17 | min-height: 100%; 18 | } 19 | 20 | body { 21 | margin-bottom: 60px; 22 | } -------------------------------------------------------------------------------- /Projects/MySession/MySession/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daohainam/lets-learn-aspnet/ee9bcdf96c487cd2a270c660f5ff468f776241a0/Projects/MySession/MySession/wwwroot/favicon.ico -------------------------------------------------------------------------------- /Projects/MySession/MySession/wwwroot/js/site.js: -------------------------------------------------------------------------------- 1 | // Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | // for details on configuring this project to bundle and minify static web assets. 3 | 4 | // Write your JavaScript code. 5 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/wwwroot/lib/bootstrap/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2021 Twitter, Inc. 4 | Copyright (c) 2011-2021 The Bootstrap Authors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) .NET Foundation and Contributors 4 | 5 | All rights reserved. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/wwwroot/lib/jquery-validation/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright Jörn Zaefferer 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Projects/MySession/MySession/wwwroot/lib/jquery/LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Copyright OpenJS Foundation and other contributors, https://openjsf.org/ 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Projects/MySession/MySessionIntegrationTest/MySessionIntegrationTest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | false 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Projects/MySession/MySessionIntegrationTest/SessionTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc.Testing; 2 | using System.Net; 3 | 4 | namespace MySessionIntegrationTest 5 | { 6 | public class SessionTests: IClassFixture> 7 | { 8 | private readonly HttpClient factory; 9 | 10 | public SessionTests(WebApplicationFactory factory) 11 | { 12 | this.factory = factory.CreateClient(); 13 | } 14 | 15 | [Fact] 16 | public async Task Call_TestGetSession_Returns_Ok_Async() 17 | { 18 | var response = await factory.GetAsync("/Test/TestGetSession"); 19 | Assert.Equal(HttpStatusCode.OK, response.StatusCode); 20 | } 21 | 22 | [Fact] 23 | public async Task Call_Set_And_Get_SessionValueAsync_Returns_Ok_Async() 24 | { 25 | string randomValue = Guid.NewGuid().ToString(); 26 | 27 | await factory.GetAsync($"/Test/SetSessionValue?key=TEST-KEY&value={randomValue}"); 28 | 29 | var response = await factory.GetAsync("/Test/GetSessionValue?key=TEST-KEY"); 30 | var responseString = await response.Content.ReadAsStringAsync(); 31 | 32 | Assert.Equal(HttpStatusCode.OK, response.StatusCode); 33 | Assert.Equal(randomValue, responseString); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/AccountDemo.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/Controllers/AccountController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authentication; 2 | using Microsoft.AspNetCore.Authentication.Cookies; 3 | using Microsoft.AspNetCore.Mvc; 4 | using SignInSignOutDemo.Models; 5 | using System.Security.Claims; 6 | using UserStorage; 7 | 8 | namespace SignInSignOutDemo.Controllers 9 | { 10 | public class AccountController : Controller 11 | { 12 | private readonly IUserRepository _userRepository; 13 | 14 | public AccountController(IUserRepository userRepository) 15 | { 16 | _userRepository = userRepository; 17 | } 18 | 19 | [HttpGet] 20 | public IActionResult LogOn() 21 | { 22 | return View(); 23 | } 24 | 25 | [HttpPost] 26 | public async Task LogOnAsync(LogOnModel model) 27 | { 28 | if (!ModelState.IsValid) 29 | { 30 | return View(model); 31 | } 32 | 33 | var user = await _userRepository.FindByUserNameAsync(model.UserName); 34 | if (user == null) 35 | { 36 | ModelState.AddModelError("UserName", "User not found"); 37 | return View(model); 38 | } 39 | 40 | var claims = new List 41 | { 42 | new(ClaimTypes.Sid, user.UserName), 43 | new(ClaimTypes.Name, user.UserName), 44 | new(ClaimTypes.Email, user.Email), 45 | new(ClaimTypes.MobilePhone, user.PhoneNumber) 46 | }; 47 | 48 | foreach (var role in user.Roles) 49 | { 50 | claims.Add(new Claim(ClaimTypes.Role, role)); 51 | } 52 | 53 | var principal = new ClaimsPrincipal(new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme)); 54 | 55 | await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal); 56 | 57 | return RedirectToAction("Index", "Profile"); 58 | } 59 | 60 | [HttpGet] 61 | public async Task LogOff() 62 | { 63 | await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); 64 | 65 | return RedirectToAction("Index", "Home"); 66 | } 67 | 68 | [HttpGet] 69 | public IActionResult Register() 70 | { 71 | return View(); 72 | } 73 | 74 | [HttpPost] 75 | public async Task RegisterAsync(RegisterModel model) 76 | { 77 | if (!ModelState.IsValid) 78 | { 79 | return View(model); 80 | } 81 | 82 | if (!IsValidUserName(model.UserName)) 83 | { 84 | ModelState.AddModelError("UserName", "User name can contain only letters, digits and hypen"); 85 | return View(model); 86 | } 87 | 88 | var user = new User 89 | { 90 | UserName = model.UserName, 91 | Email = model.Email ?? "", 92 | PhoneNumber = model.PhoneNumber ?? "", 93 | Password = model.Password ?? "", 94 | Roles = ["User"] 95 | }; 96 | 97 | await _userRepository.SaveAsync(user); 98 | return RedirectToAction("LogOn"); 99 | } 100 | 101 | private static bool IsValidUserName(string userName) 102 | { 103 | return userName.All((c) => char.IsAsciiLetterOrDigit(c) || c == '-'); 104 | } 105 | 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using Microsoft.AspNetCore.Mvc; 3 | using SignInSignOutDemo.Models; 4 | 5 | namespace SignInSignOutDemo.Controllers 6 | { 7 | public class HomeController : Controller 8 | { 9 | private readonly ILogger _logger; 10 | 11 | public HomeController(ILogger logger) 12 | { 13 | _logger = logger; 14 | } 15 | 16 | public IActionResult Index() 17 | { 18 | return View(); 19 | } 20 | 21 | public IActionResult Privacy() 22 | { 23 | return View(); 24 | } 25 | 26 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] 27 | public IActionResult Error() 28 | { 29 | return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/Controllers/ProfileController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | using Microsoft.AspNetCore.Mvc; 3 | using SignInSignOutDemo.Models; 4 | using UserStorage; 5 | 6 | namespace SignInSignOutDemo.Controllers 7 | { 8 | [Authorize] 9 | public class ProfileController : Controller 10 | { 11 | private readonly IUserRepository _userRepository; 12 | 13 | public ProfileController(IUserRepository userRepository) 14 | { 15 | _userRepository = userRepository; 16 | } 17 | 18 | public async Task IndexAsync() 19 | { 20 | var user = await _userRepository.FindByUserNameAsync(User.Identity!.Name!); 21 | if (user == null) 22 | { 23 | return NotFound(); 24 | } 25 | 26 | var model = new UserProfileModel 27 | { 28 | UserName = user.UserName, 29 | Email = user.Email, 30 | PhoneNumber = user.PhoneNumber, 31 | Roles = user.Roles, 32 | Password = user.Password 33 | }; 34 | 35 | return View(model); 36 | } 37 | 38 | [HttpPost] 39 | public async Task SaveAsync(UserProfileModel model) 40 | { 41 | if (!ModelState.IsValid) 42 | { 43 | return View("Index", model); 44 | } 45 | 46 | if (!IsValidUserName(model.UserName)) 47 | { 48 | ModelState.AddModelError("UserName", "User name can contain only letters, digits and hypen"); 49 | return View("Index", model); 50 | } 51 | 52 | var user = new User 53 | { 54 | UserName = model.UserName, 55 | Email = model.Email ?? "", 56 | PhoneNumber = model.PhoneNumber ?? "", 57 | Roles = model.Roles, 58 | Password = model.Password ?? "" 59 | }; 60 | await _userRepository.SaveAsync(user); 61 | 62 | return RedirectToAction("Index"); 63 | } 64 | private static bool IsValidUserName(string userName) 65 | { 66 | return userName.All((c) => char.IsAsciiLetterOrDigit(c) || c == '-'); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/Models/ErrorViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace SignInSignOutDemo.Models 2 | { 3 | public class ErrorViewModel 4 | { 5 | public string? RequestId { get; set; } 6 | 7 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/Models/LogOnModel.cs: -------------------------------------------------------------------------------- 1 | namespace SignInSignOutDemo.Models 2 | { 3 | public class LogOnModel 4 | { 5 | public string UserName { get; set; } = string.Empty; 6 | public string Password { get; set; } = string.Empty; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/Models/RegisterModel.cs: -------------------------------------------------------------------------------- 1 | namespace SignInSignOutDemo.Models 2 | { 3 | public class RegisterModel 4 | { 5 | public string UserName { get; set; } = string.Empty; 6 | public string? Email { get; set; } 7 | public string? PhoneNumber { get; set; } 8 | public string? Password { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/Models/UserProfileModel.cs: -------------------------------------------------------------------------------- 1 | namespace SignInSignOutDemo.Models 2 | { 3 | public class UserProfileModel 4 | { 5 | public string UserName { get; set; } = string.Empty; 6 | public string? Email { get; set; } 7 | public string? PhoneNumber { get; set; } 8 | public string? Password { get; set; } 9 | public List Roles { get; set; } = []; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authentication.Cookies; 2 | using UserStorage; 3 | 4 | var builder = WebApplication.CreateBuilder(args); 5 | 6 | // Add services to the container. 7 | builder.Services.AddControllersWithViews(); 8 | 9 | builder.Services.Configure(builder.Configuration.GetSection("JsonDatabaseOptions")); 10 | builder.Services.AddScoped(); 11 | 12 | builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) 13 | .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, (options) => 14 | { 15 | options.LoginPath = "/Account/LogOn"; 16 | options.AccessDeniedPath = "/Account/LogOn"; 17 | options.LogoutPath = "/Account/LogOff"; 18 | options.Cookie.Name = "AccountDemo.Cookie"; 19 | }); 20 | 21 | var app = builder.Build(); 22 | 23 | // Configure the HTTP request pipeline. 24 | if (!app.Environment.IsDevelopment()) 25 | { 26 | app.UseExceptionHandler("/Home/Error"); 27 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. 28 | app.UseHsts(); 29 | } 30 | 31 | app.UseHttpsRedirection(); 32 | app.UseStaticFiles(); 33 | 34 | app.UseRouting(); 35 | 36 | app.UseAuthentication(); 37 | app.UseAuthorization(); 38 | 39 | app.MapControllerRoute( 40 | name: "default", 41 | pattern: "{controller=Home}/{action=Index}/{id?}"); 42 | 43 | app.Run(); 44 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:8191", 8 | "sslPort": 44392 9 | } 10 | }, 11 | "profiles": { 12 | "http": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "applicationUrl": "http://localhost:5098", 17 | "environmentVariables": { 18 | "ASPNETCORE_ENVIRONMENT": "Development" 19 | } 20 | }, 21 | "https": { 22 | "commandName": "Project", 23 | "dotnetRunMessages": true, 24 | "launchBrowser": true, 25 | "applicationUrl": "https://localhost:7280;http://localhost:5098", 26 | "environmentVariables": { 27 | "ASPNETCORE_ENVIRONMENT": "Development" 28 | } 29 | }, 30 | "IIS Express": { 31 | "commandName": "IISExpress", 32 | "launchBrowser": true, 33 | "environmentVariables": { 34 | "ASPNETCORE_ENVIRONMENT": "Development" 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/Views/Account/LogOn.cshtml: -------------------------------------------------------------------------------- 1 | @model SignInSignOutDemo.Models.LogOnModel 2 | 3 | @{ 4 | ViewData["Title"] = "LogOn"; 5 | Layout = "~/Views/Shared/_Layout.cshtml"; 6 | } 7 | 8 |

Log On

9 |
10 |
11 |
12 |
13 |
14 |
15 | 16 | 17 | 18 |
19 |
20 | 21 | 22 | 23 |
24 |
25 | 26 |
27 |
28 |
29 |
30 | 31 | @section Scripts { 32 | @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} 33 | } 34 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/Views/Account/Register.cshtml: -------------------------------------------------------------------------------- 1 | @model SignInSignOutDemo.Models.UserProfileModel 2 | 3 | @{ 4 | ViewData["Title"] = "Register"; 5 | Layout = "~/Views/Shared/_Layout.cshtml"; 6 | } 7 | 8 |

Register

9 |
10 |
11 |
12 |
13 |
14 |
15 | 16 | 17 | 18 |
19 |
20 | 21 | 22 | 23 |
24 |
25 | 26 | 27 | 28 |
29 |
30 | 31 | 32 | 33 |
34 |
35 | 36 |
37 |
38 |
39 |
40 | 41 | @section Scripts { 42 | @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} 43 | } 44 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Home Page"; 3 | } 4 | 5 |
6 |

ASP.NET Account demo

7 |
8 |

ASP.NET Account demo is a simple web application that demonstrates how to create a user account and log in to the application.

9 |

Click the Register link to create a new user account.

10 |

Click the Log On link to log in to the application.

11 |

Click the Log Off link to log out of the application.

12 |
13 |

Current user: @(User.Identity?.Name ?? "")

14 |
15 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/Views/Home/Privacy.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Privacy Policy"; 3 | } 4 |

@ViewData["Title"]

5 | 6 |

Use this page to detail your site's privacy policy.

7 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/Views/Profile/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model SignInSignOutDemo.Models.UserProfileModel 2 | 3 | @{ 4 | ViewData["Title"] = "Index"; 5 | Layout = "~/Views/Shared/_Layout.cshtml"; 6 | } 7 | 8 |

User Profile

9 |
10 |
11 |
12 |
13 |
14 |
15 | 16 | 17 | 18 |
19 |
20 | 21 | 22 | 23 |
24 |
25 | 26 | 27 | 28 |
29 |
30 | 31 | 32 | 33 |
34 |
35 | 36 |
37 |
38 |
39 |
40 | 41 | @section Scripts { 42 | @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} 43 | } 44 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @model ErrorViewModel 2 | @{ 3 | ViewData["Title"] = "Error"; 4 | } 5 | 6 |

Error.

7 |

An error occurred while processing your request.

8 | 9 | @if (Model.ShowRequestId) 10 | { 11 |

12 | Request ID: @Model.RequestId 13 |

14 | } 15 | 16 |

Development Mode

17 |

18 | Swapping to Development environment will display more detailed information about the error that occurred. 19 |

20 |

21 | The Development environment shouldn't be enabled for deployed applications. 22 | It can result in displaying sensitive information from exceptions to end users. 23 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development 24 | and restarting the app. 25 |

26 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewData["Title"] - SignInSignOutDemo 7 | 8 | 9 | 10 | 11 | 12 |
13 | 50 |
51 |
52 |
53 | @RenderBody() 54 |
55 |
56 | 57 |
58 |
59 | © 2024 - SignInSignOutDemo - Privacy 60 |
61 |
62 | 63 | 64 | 65 | @await RenderSectionAsync("Scripts", required: false) 66 | 67 | 68 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/Views/Shared/_Layout.cshtml.css: -------------------------------------------------------------------------------- 1 | /* Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | for details on configuring this project to bundle and minify static web assets. */ 3 | 4 | a.navbar-brand { 5 | white-space: normal; 6 | text-align: center; 7 | word-break: break-all; 8 | } 9 | 10 | a { 11 | color: #0077cc; 12 | } 13 | 14 | .btn-primary { 15 | color: #fff; 16 | background-color: #1b6ec2; 17 | border-color: #1861ac; 18 | } 19 | 20 | .nav-pills .nav-link.active, .nav-pills .show > .nav-link { 21 | color: #fff; 22 | background-color: #1b6ec2; 23 | border-color: #1861ac; 24 | } 25 | 26 | .border-top { 27 | border-top: 1px solid #e5e5e5; 28 | } 29 | .border-bottom { 30 | border-bottom: 1px solid #e5e5e5; 31 | } 32 | 33 | .box-shadow { 34 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05); 35 | } 36 | 37 | button.accept-policy { 38 | font-size: 1rem; 39 | line-height: inherit; 40 | } 41 | 42 | .footer { 43 | position: absolute; 44 | bottom: 0; 45 | width: 100%; 46 | white-space: nowrap; 47 | line-height: 60px; 48 | } 49 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/Views/Shared/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using SignInSignOutDemo 2 | @using SignInSignOutDemo.Models 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*", 9 | "JsonDatabaseOptions": { 10 | "DatabasePath": ".\\UserJsonDb" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-size: 14px; 3 | } 4 | 5 | @media (min-width: 768px) { 6 | html { 7 | font-size: 16px; 8 | } 9 | } 10 | 11 | .btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus { 12 | box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb; 13 | } 14 | 15 | html { 16 | position: relative; 17 | min-height: 100%; 18 | } 19 | 20 | body { 21 | margin-bottom: 60px; 22 | } -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daohainam/lets-learn-aspnet/ee9bcdf96c487cd2a270c660f5ff468f776241a0/Projects/SecurityDemo/AccountDemo/wwwroot/favicon.ico -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/wwwroot/js/site.js: -------------------------------------------------------------------------------- 1 | // Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | // for details on configuring this project to bundle and minify static web assets. 3 | 4 | // Write your JavaScript code. 5 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/wwwroot/lib/bootstrap/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2021 Twitter, Inc. 4 | Copyright (c) 2011-2021 The Bootstrap Authors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) .NET Foundation and Contributors 4 | 5 | All rights reserved. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/wwwroot/lib/jquery-validation/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright Jörn Zaefferer 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/AccountDemo/wwwroot/lib/jquery/LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Copyright OpenJS Foundation and other contributors, https://openjsf.org/ 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Projects/SecurityDemo/SecurityDemo.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.12.35506.116 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UserStorage", "UserStorage\UserStorage.csproj", "{4EE89526-D63B-4C6A-944A-BF119C045DDB}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AccountDemo", "AccountDemo\AccountDemo.csproj", "{727734C2-A428-420C-ADE9-5BF3601A131F}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {4EE89526-D63B-4C6A-944A-BF119C045DDB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {4EE89526-D63B-4C6A-944A-BF119C045DDB}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {4EE89526-D63B-4C6A-944A-BF119C045DDB}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {4EE89526-D63B-4C6A-944A-BF119C045DDB}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {727734C2-A428-420C-ADE9-5BF3601A131F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {727734C2-A428-420C-ADE9-5BF3601A131F}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {727734C2-A428-420C-ADE9-5BF3601A131F}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {727734C2-A428-420C-ADE9-5BF3601A131F}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/UserStorage/IUserRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace UserStorage 8 | { 9 | public interface IUserRepository 10 | { 11 | public Task FindByUserNameAsync(string userName); 12 | public Task SaveAsync(User user); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/UserStorage/JsonFileUserRepository.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Options; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Text.Json; 7 | using System.Threading.Tasks; 8 | 9 | namespace UserStorage 10 | { 11 | public class JsonFileUserRepository: IUserRepository 12 | { 13 | private readonly string _dbPath; 14 | public JsonFileUserRepository(IOptions options) 15 | { 16 | _dbPath = options.Value.DatabasePath; 17 | 18 | if (!Directory.Exists(_dbPath)) { 19 | Directory.CreateDirectory(_dbPath); 20 | } 21 | } 22 | 23 | public async Task FindByUserNameAsync(string userName) 24 | { 25 | ArgumentNullException.ThrowIfNull(userName, nameof(userName)); 26 | if (!IsValidUserName(userName)) 27 | { 28 | throw new ArgumentException("Invalid user name", nameof(userName)); 29 | } 30 | 31 | var fileInfo = new FileInfo(Path.Combine(_dbPath, userName)); 32 | if (!fileInfo.Exists) 33 | { 34 | return null; 35 | } 36 | 37 | var json = await File.ReadAllTextAsync(fileInfo.FullName); 38 | return JsonSerializer.Deserialize(json); 39 | } 40 | 41 | public Task SaveAsync(User user) 42 | { 43 | ArgumentNullException.ThrowIfNull(user, nameof(user)); 44 | 45 | if (!IsValidUserName(user.UserName)) 46 | { 47 | throw new ArgumentException("Invalid user name", nameof(user)); 48 | } 49 | 50 | var fileInfo = new FileInfo(Path.Combine(_dbPath, user.UserName)); 51 | var json = JsonSerializer.Serialize(user); 52 | 53 | return File.WriteAllTextAsync(fileInfo.FullName, json); 54 | } 55 | 56 | private static bool IsValidUserName(string userName) 57 | { 58 | return userName.All((c) => char.IsAsciiLetterOrDigit(c) || c == '-'); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/UserStorage/JsonFileUserRepositoryOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace UserStorage 8 | { 9 | public class JsonFileUserRepositoryOptions 10 | { 11 | public string DatabasePath { get; set; } = string.Empty; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/UserStorage/User.cs: -------------------------------------------------------------------------------- 1 | namespace UserStorage 2 | { 3 | public class User 4 | { 5 | public string UserName { get; set; } = string.Empty; 6 | public string Email { get; set; } = string.Empty; 7 | public string PhoneNumber { get; set; } = string.Empty; 8 | public string Password { get; set; } = string.Empty; 9 | public List Roles { get; set; } = []; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Projects/SecurityDemo/UserStorage/UserStorage.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Projects/TodoApi/IntegrationTests/ApiIntegrationTests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using Microsoft.AspNetCore.Mvc.Testing; 3 | using System.Net; 4 | using System.Net.Http.Json; 5 | using TodoApi; 6 | using ToDoRepository; 7 | 8 | namespace IntegrationTests 9 | { 10 | public class ApiIntegrationTests: IClassFixture> 11 | { 12 | private readonly WebApplicationFactory _factory; 13 | 14 | public ApiIntegrationTests(WebApplicationFactory factory) 15 | { 16 | _factory = factory; 17 | } 18 | 19 | [Fact] 20 | public async Task Test1() 21 | { 22 | var client = _factory.CreateClient(); 23 | 24 | var id = Guid.NewGuid(); 25 | var response = await client.GetAsync($"/api/todoitems/{id:D}"); 26 | 27 | response.StatusCode.Should().Be(HttpStatusCode.NotFound); 28 | 29 | var item = new ToDoItem { Id = id, Name = GenerateRandomString(), IsComplete = false }; 30 | var createResponse = await client.PostAsJsonAsync("/api/todoitems", item); 31 | 32 | createResponse.EnsureSuccessStatusCode(); 33 | 34 | var createdItem = await createResponse.Content.ReadFromJsonAsync(); 35 | createdItem.Should().NotBeNull(); 36 | createdItem!.Id.Should().Be(id); 37 | createdItem.Name.Should().Be(item.Name); 38 | createdItem.IsComplete.Should().Be(item.IsComplete); 39 | 40 | var getResponse = await client.GetAsync($"/api/todoitems/{id:D}"); 41 | getResponse.EnsureSuccessStatusCode(); 42 | var getItem = await getResponse.Content.ReadFromJsonAsync(); 43 | 44 | getItem.Should().NotBeNull(); 45 | getItem!.Id.Should().Be(id); 46 | getItem.Name.Should().Be(item.Name); 47 | getItem.IsComplete.Should().Be(item.IsComplete); 48 | 49 | var deleteResponse = await client.DeleteAsync($"/api/todoitems/{id:D}"); 50 | deleteResponse.EnsureSuccessStatusCode(); 51 | 52 | getResponse = await client.GetAsync($"/api/todoitems/{id:D}"); 53 | getResponse.StatusCode.Should().Be(HttpStatusCode.NotFound); 54 | } 55 | 56 | private static string GenerateRandomString(int length = 50) 57 | { 58 | const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 59 | var random = new Random(); 60 | return new string(Enumerable.Repeat(chars, length) 61 | .Select(s => s[random.Next(s.Length)]).ToArray()); 62 | } 63 | 64 | } 65 | } -------------------------------------------------------------------------------- /Projects/TodoApi/IntegrationTests/IntegrationTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | false 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Projects/TodoApi/RepositoryTests/MOngoDbRepositoryUnitTest.cs: -------------------------------------------------------------------------------- 1 | using ToDoRepository; 2 | using FluentAssertions; 3 | 4 | namespace RepositoryTests 5 | { 6 | public class MongoDbTodoRepositoryTests 7 | { 8 | [Fact] 9 | public async Task CreateTodoItemAsync() 10 | { 11 | // Arrange 12 | var repository = new MongoDbToDoRepository( 13 | new MongoDbToDoRepositoryOptions 14 | { 15 | ConnectionString = "mongodb://localhost:27017", 16 | DatabaseName = "TodoApi" 17 | } 18 | ); 19 | var item = new ToDoItem { Id = Guid.NewGuid(), Name = "Test Item", IsComplete = false }; 20 | // Act 21 | var result = await repository.CreateTodoItemAsync(item); 22 | // Assert 23 | result.Should().NotBeNull(); 24 | result.Id.Should().NotBe(Guid.Empty); 25 | result.Name.Should().Be(item.Name); 26 | result.IsComplete.Should().Be(item.IsComplete); 27 | 28 | var createdItem = await repository.GetTodoItemAsync(result.Id); 29 | createdItem.Should().NotBeNull(); 30 | createdItem!.Id.Should().Be(result.Id); 31 | createdItem.Name.Should().Be(result.Name); 32 | createdItem.IsComplete.Should().Be(result.IsComplete); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /Projects/TodoApi/RepositoryTests/RepositoryTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | false 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Projects/TodoApi/ToDoRepository.Abstractions/IToDoRepository.cs: -------------------------------------------------------------------------------- 1 | namespace ToDoRepository 2 | { 3 | public interface IToDoRepository 4 | { 5 | Task CreateTodoItemAsync(ToDoItem item); 6 | Task DeleteTodoItemAsync(Guid id); 7 | Task GetTodoItemAsync(Guid id); 8 | Task> GetTodoItemsAsync(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Projects/TodoApi/ToDoRepository.Abstractions/ToDoItem.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson.Serialization.Attributes; 2 | 3 | namespace ToDoRepository 4 | { 5 | public class ToDoItem 6 | { 7 | [BsonGuidRepresentation(MongoDB.Bson.GuidRepresentation.Standard)] public Guid Id { get; set; } 8 | public string? Name { get; set; } 9 | public bool IsComplete { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Projects/TodoApi/ToDoRepository.Abstractions/ToDoRepository.Abstractions.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | ToDoRepository 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Projects/TodoApi/ToDoRepository.MongoDb/MongoDbToDoRepository.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Driver; 2 | 3 | namespace ToDoRepository 4 | { 5 | public class MongoDbToDoRepository : IToDoRepository 6 | { 7 | private readonly IMongoCollection collection; 8 | 9 | public MongoDbToDoRepository(MongoDbToDoRepositoryOptions options) 10 | { 11 | var client = new MongoClient(options.ConnectionString); 12 | var database = client.GetDatabase(options.DatabaseName); 13 | collection = database.GetCollection("TodoItems"); 14 | } 15 | 16 | public async Task CreateTodoItemAsync(ToDoItem item) 17 | { 18 | await collection.InsertOneAsync(item); 19 | return item; 20 | } 21 | 22 | public async Task DeleteTodoItemAsync(Guid id) 23 | { 24 | var result = await collection.DeleteOneAsync(item => item.Id == id); 25 | 26 | return (int)result.DeletedCount; 27 | } 28 | 29 | public async Task GetTodoItemAsync(Guid id) 30 | { 31 | return await collection.Find(item => item.Id == id).FirstOrDefaultAsync(); 32 | } 33 | 34 | public async Task> GetTodoItemsAsync() 35 | { 36 | return await collection.Find(item => true).ToListAsync(); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Projects/TodoApi/ToDoRepository.MongoDb/MongoDbToDoRepositoryOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ToDoRepository 8 | { 9 | public class MongoDbToDoRepositoryOptions 10 | { 11 | public required string ConnectionString { get; set; } 12 | public required string DatabaseName { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Projects/TodoApi/ToDoRepository.MongoDb/ToDoRepository.MongoDb.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | ToDoRepository 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Projects/TodoApi/TodoApi.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.12.35527.113 d17.12 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TodoApi", "TodoApi\TodoApi.csproj", "{4F106916-1CE8-4107-8706-DF2E37466392}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RepositoryTests", "RepositoryTests\RepositoryTests.csproj", "{ED8F10AA-2F46-41AB-A0B0-CE277BF9C6D9}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ToDoRepository.Abstractions", "ToDoRepository.Abstractions\ToDoRepository.Abstractions.csproj", "{644DDA82-6301-4E7E-B9EC-C0C41FBFC479}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ToDoRepository.MongoDb", "ToDoRepository.MongoDb\ToDoRepository.MongoDb.csproj", "{6682B843-17E4-4A69-B136-3AF787B3572A}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IntegrationTests", "IntegrationTests\IntegrationTests.csproj", "{33888853-B231-4CFE-BB8E-E500C2562CE7}" 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Release|Any CPU = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {4F106916-1CE8-4107-8706-DF2E37466392}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {4F106916-1CE8-4107-8706-DF2E37466392}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {4F106916-1CE8-4107-8706-DF2E37466392}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {4F106916-1CE8-4107-8706-DF2E37466392}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {ED8F10AA-2F46-41AB-A0B0-CE277BF9C6D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {ED8F10AA-2F46-41AB-A0B0-CE277BF9C6D9}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {ED8F10AA-2F46-41AB-A0B0-CE277BF9C6D9}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {ED8F10AA-2F46-41AB-A0B0-CE277BF9C6D9}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {644DDA82-6301-4E7E-B9EC-C0C41FBFC479}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {644DDA82-6301-4E7E-B9EC-C0C41FBFC479}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {644DDA82-6301-4E7E-B9EC-C0C41FBFC479}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {644DDA82-6301-4E7E-B9EC-C0C41FBFC479}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {6682B843-17E4-4A69-B136-3AF787B3572A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {6682B843-17E4-4A69-B136-3AF787B3572A}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {6682B843-17E4-4A69-B136-3AF787B3572A}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {6682B843-17E4-4A69-B136-3AF787B3572A}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {33888853-B231-4CFE-BB8E-E500C2562CE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {33888853-B231-4CFE-BB8E-E500C2562CE7}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {33888853-B231-4CFE-BB8E-E500C2562CE7}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {33888853-B231-4CFE-BB8E-E500C2562CE7}.Release|Any CPU.Build.0 = Release|Any CPU 42 | EndGlobalSection 43 | GlobalSection(SolutionProperties) = preSolution 44 | HideSolutionNode = FALSE 45 | EndGlobalSection 46 | EndGlobal 47 | -------------------------------------------------------------------------------- /Projects/TodoApi/TodoApi/Controllers/TodoController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using ToDoRepository; 3 | 4 | namespace TodoApi.Controllers 5 | { 6 | [Route("/api/todoitems")] 7 | [ApiController] 8 | public class TodoController : ControllerBase 9 | { 10 | private readonly IToDoRepository todoRepository; 11 | 12 | public TodoController(IToDoRepository todoRepository) { 13 | this.todoRepository = todoRepository; 14 | } 15 | 16 | [HttpGet] 17 | public async Task GetTodoItems() 18 | { 19 | return Ok(await todoRepository.GetTodoItemsAsync()); 20 | } 21 | [HttpGet("{id}")] 22 | public async Task GetTodoItemAsync(Guid id) 23 | { 24 | var item = await todoRepository.GetTodoItemAsync(id); 25 | 26 | if (item == null) return NotFound(); 27 | 28 | return Ok(item); 29 | } 30 | [HttpPost] 31 | public async Task CreateTodoItemAsync(ToDoItem item) 32 | { 33 | return Ok(await todoRepository.CreateTodoItemAsync(item)); 34 | } 35 | [HttpPut("{id}")] 36 | public IActionResult UpdateTodoItem(int id) 37 | { 38 | return Ok($"UpdateTodoItem {id}"); 39 | } 40 | [HttpDelete("{id}")] 41 | public async Task DeleteTodoItem(Guid id) 42 | { 43 | int r = await todoRepository.DeleteTodoItemAsync(id); 44 | 45 | return r == 0 ? NotFound() : Ok(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Projects/TodoApi/TodoApi/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Configuration; 2 | using MongoDB.Driver; 3 | using ToDoRepository; 4 | 5 | namespace TodoApi 6 | { 7 | public class Program 8 | { 9 | public static void Main(string[] args) 10 | { 11 | var builder = WebApplication.CreateBuilder(args); 12 | 13 | // Add services to the container. 14 | 15 | builder.Services.AddControllers(); 16 | builder.Services.AddSingleton(new MongoDbToDoRepositoryOptions 17 | { 18 | ConnectionString = builder.Configuration.GetConnectionString("TodoApiDatabase")!, 19 | DatabaseName = builder.Configuration["TodoApiDatabaseName"]! 20 | }); 21 | builder.Services.AddTransient(); 22 | 23 | var app = builder.Build(); 24 | 25 | // Configure the HTTP request pipeline. 26 | 27 | app.UseHttpsRedirection(); 28 | 29 | app.UseAuthorization(); 30 | 31 | 32 | app.MapControllers(); 33 | 34 | app.Run(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Projects/TodoApi/TodoApi/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:48586", 8 | "sslPort": 44357 9 | } 10 | }, 11 | "profiles": { 12 | "http": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "launchUrl": "weatherforecast", 17 | "applicationUrl": "http://localhost:5110", 18 | "environmentVariables": { 19 | "ASPNETCORE_ENVIRONMENT": "Development" 20 | } 21 | }, 22 | "https": { 23 | "commandName": "Project", 24 | "dotnetRunMessages": true, 25 | "launchBrowser": true, 26 | "launchUrl": "weatherforecast", 27 | "applicationUrl": "https://localhost:7287;http://localhost:5110", 28 | "environmentVariables": { 29 | "ASPNETCORE_ENVIRONMENT": "Development" 30 | } 31 | }, 32 | "IIS Express": { 33 | "commandName": "IISExpress", 34 | "launchBrowser": true, 35 | "launchUrl": "weatherforecast", 36 | "environmentVariables": { 37 | "ASPNETCORE_ENVIRONMENT": "Development" 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Projects/TodoApi/TodoApi/TodoApi.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Projects/TodoApi/TodoApi/TodoApi.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | https 5 | ApiControllerEmptyScaffolder 6 | root/Common/Api 7 | 8 | -------------------------------------------------------------------------------- /Projects/TodoApi/TodoApi/TodoApi.http: -------------------------------------------------------------------------------- 1 | @TodoApi_HostAddress = http://localhost:5110 2 | 3 | GET {{TodoApi_HostAddress}}/weatherforecast/ 4 | Accept: application/json 5 | 6 | ### 7 | -------------------------------------------------------------------------------- /Projects/TodoApi/TodoApi/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*", 9 | "ConnectionStrings": { 10 | "TodoApiDatabase": "mongodb://localhost:27017" 11 | }, 12 | "TodoApiDatabaseName": "TodoApiDatabase" 13 | } 14 | -------------------------------------------------------------------------------- /Projects/TodoApi/TodoApi/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /Projects/TodoList/Entities/Entities.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Projects/TodoList/Entities/TodoItem.cs: -------------------------------------------------------------------------------- 1 | namespace Entities 2 | { 3 | public class TodoItem 4 | { 5 | public int Id { get; set; } 6 | public string Text { get; set; } = string.Empty; 7 | public bool IsCompleted { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Projects/TodoList/Infratructure/InMemoryToDoItemRepository.cs: -------------------------------------------------------------------------------- 1 | using Entities; 2 | using UseCases; 3 | 4 | namespace Infratructure 5 | { 6 | public class InMemoryToDoItemRepository : IToDoItemRepository 7 | { 8 | private readonly List _items; 9 | 10 | public InMemoryToDoItemRepository() 11 | { 12 | _items = []; 13 | } 14 | 15 | public void Add(TodoItem item) 16 | { 17 | _items.Add(item); 18 | } 19 | 20 | public void Delete(int id) 21 | { 22 | var item = _items.FirstOrDefault(i => i.Id == id); 23 | if (item != null) 24 | { 25 | _items.Remove(item); 26 | } 27 | } 28 | 29 | public TodoItem? GetById(int id) 30 | { 31 | return _items.FirstOrDefault(i => i.Id == id); 32 | } 33 | 34 | public IEnumerable GetItems() 35 | { 36 | return _items; 37 | } 38 | 39 | public void Update(TodoItem item) 40 | { 41 | var existingItem = _items.FirstOrDefault(i => i.Id == item.Id); 42 | if (existingItem != null) 43 | { 44 | existingItem.Text = item.Text; 45 | existingItem.IsCompleted = item.IsCompleted; 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Projects/TodoList/Infratructure/Infratructure.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Projects/TodoList/TestProject/TestProject.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | false 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Projects/TodoList/TestProject/UnitTest1.cs: -------------------------------------------------------------------------------- 1 | using Entities; 2 | using Infratructure; 3 | using UseCases; 4 | 5 | namespace TestProject 6 | { 7 | public class UnitTest1 8 | { 9 | [Fact] 10 | public void CreateTodoItem_And_Set_Completed_Test() 11 | { 12 | // Arrange 13 | var mockRepository = new InMemoryToDoItemRepository(); 14 | var todoListManager = new TodoListManager(mockRepository); 15 | 16 | var todoItem = new TodoItem { Id = 1, Text = "Test Item", IsCompleted = false }; 17 | 18 | // Act 19 | todoListManager.AddTodoItem(todoItem); 20 | todoListManager.MarkComplete(1); 21 | 22 | // Assert 23 | Assert.True(todoListManager.GetTodoItems().First().IsCompleted); 24 | Assert.Equal("Test Item", todoListManager.GetTodoItems().First().Text); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /Projects/TodoList/TodoList.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.11.35222.181 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Entities", "Entities\Entities.csproj", "{53B5B69B-7A2B-46C2-97BC-88C7C8F98D58}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UseCases", "UseCases\UseCases.csproj", "{65A53844-1CF0-448F-B0C1-85197B012DDF}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Infratructure", "Infratructure\Infratructure.csproj", "{F136BF63-8EBC-427A-A94B-98487DABAAA2}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TodoList", "TodoList\TodoList.csproj", "{B531744E-5E1D-4CA5-8F46-CF4B2113BD08}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestProject", "TestProject\TestProject.csproj", "{F369D9A5-1378-46E9-AA25-440A12F2B37F}" 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Release|Any CPU = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {53B5B69B-7A2B-46C2-97BC-88C7C8F98D58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {53B5B69B-7A2B-46C2-97BC-88C7C8F98D58}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {53B5B69B-7A2B-46C2-97BC-88C7C8F98D58}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {53B5B69B-7A2B-46C2-97BC-88C7C8F98D58}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {65A53844-1CF0-448F-B0C1-85197B012DDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {65A53844-1CF0-448F-B0C1-85197B012DDF}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {65A53844-1CF0-448F-B0C1-85197B012DDF}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {65A53844-1CF0-448F-B0C1-85197B012DDF}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {F136BF63-8EBC-427A-A94B-98487DABAAA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {F136BF63-8EBC-427A-A94B-98487DABAAA2}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {F136BF63-8EBC-427A-A94B-98487DABAAA2}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {F136BF63-8EBC-427A-A94B-98487DABAAA2}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {B531744E-5E1D-4CA5-8F46-CF4B2113BD08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {B531744E-5E1D-4CA5-8F46-CF4B2113BD08}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {B531744E-5E1D-4CA5-8F46-CF4B2113BD08}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {B531744E-5E1D-4CA5-8F46-CF4B2113BD08}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {F369D9A5-1378-46E9-AA25-440A12F2B37F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {F369D9A5-1378-46E9-AA25-440A12F2B37F}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {F369D9A5-1378-46E9-AA25-440A12F2B37F}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {F369D9A5-1378-46E9-AA25-440A12F2B37F}.Release|Any CPU.Build.0 = Release|Any CPU 42 | EndGlobalSection 43 | GlobalSection(SolutionProperties) = preSolution 44 | HideSolutionNode = FALSE 45 | EndGlobalSection 46 | GlobalSection(ExtensibilityGlobals) = postSolution 47 | SolutionGuid = {C9CA404C-6BE3-4581-8712-D44AFC4CB99D} 48 | EndGlobalSection 49 | EndGlobal 50 | -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using System.Diagnostics; 3 | using TodoList.Models; 4 | using UseCases; 5 | 6 | namespace TodoList.Controllers 7 | { 8 | public class HomeController : Controller 9 | { 10 | private readonly TodoListManager _listManager; 11 | private readonly ILogger _logger; 12 | 13 | public HomeController(TodoListManager listManager, ILogger logger) 14 | { 15 | _listManager = listManager; 16 | _logger = logger; 17 | } 18 | 19 | public IActionResult Index() 20 | { 21 | var todoItems = _listManager.GetTodoItems(); 22 | 23 | return View(new TodoListViewModel() 24 | { 25 | Items = todoItems.Select(ti => new Item() 26 | { 27 | Id = ti.Id, 28 | Text = ti.Text, 29 | IsCompleted = ti.IsCompleted 30 | }) 31 | }); 32 | } 33 | 34 | [HttpGet] 35 | public IActionResult Add() 36 | { 37 | return View("Add"); 38 | } 39 | 40 | [HttpPost] 41 | public IActionResult Add(Item item) 42 | { 43 | _listManager.AddTodoItem(new TodoItem() 44 | { 45 | Id = item.Id, 46 | Text = item.Text, 47 | IsCompleted = false 48 | }); 49 | 50 | return RedirectToAction("Index"); 51 | } 52 | 53 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] 54 | public IActionResult Error() 55 | { 56 | return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using Entities; 2 | global using UseCases; 3 | global using Infratructure; -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/Models/ErrorViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace TodoList.Models 2 | { 3 | public class ErrorViewModel 4 | { 5 | public string? RequestId { get; set; } 6 | 7 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/Models/Item.cs: -------------------------------------------------------------------------------- 1 | namespace TodoList.Models 2 | { 3 | public class Item 4 | { 5 | public int Id { get; set; } 6 | public required string Text { get; set; } 7 | public bool IsCompleted { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/Models/TodoListViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace TodoList.Models 2 | { 3 | public class TodoListViewModel 4 | { 5 | public required IEnumerable Items { get; init; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/Program.cs: -------------------------------------------------------------------------------- 1 | using Infratructure; 2 | using UseCases; 3 | 4 | namespace TodoList 5 | { 6 | public class Program 7 | { 8 | public static void Main(string[] args) 9 | { 10 | var builder = WebApplication.CreateBuilder(args); 11 | 12 | // Add services to the container. 13 | builder.Services.AddControllersWithViews(); 14 | 15 | builder.Services.AddSingleton(); 16 | builder.Services.AddTransient(); 17 | 18 | var app = builder.Build(); 19 | 20 | // Configure the HTTP request pipeline. 21 | if (!app.Environment.IsDevelopment()) 22 | { 23 | app.UseExceptionHandler("/Home/Error"); 24 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. 25 | app.UseHsts(); 26 | } 27 | 28 | app.UseHttpsRedirection(); 29 | app.UseStaticFiles(); 30 | 31 | app.UseRouting(); 32 | 33 | app.UseAuthorization(); 34 | 35 | app.MapControllerRoute( 36 | name: "default", 37 | pattern: "{controller=Home}/{action=Index}/{id?}"); 38 | 39 | app.Run(); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:44932", 8 | "sslPort": 44312 9 | } 10 | }, 11 | "profiles": { 12 | "http": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "applicationUrl": "http://localhost:5188", 17 | "environmentVariables": { 18 | "ASPNETCORE_ENVIRONMENT": "Development" 19 | } 20 | }, 21 | "https": { 22 | "commandName": "Project", 23 | "dotnetRunMessages": true, 24 | "launchBrowser": true, 25 | "applicationUrl": "https://localhost:7209;http://localhost:5188", 26 | "environmentVariables": { 27 | "ASPNETCORE_ENVIRONMENT": "Development" 28 | } 29 | }, 30 | "IIS Express": { 31 | "commandName": "IISExpress", 32 | "launchBrowser": true, 33 | "environmentVariables": { 34 | "ASPNETCORE_ENVIRONMENT": "Development" 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/TodoList.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/TodoList.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | https 5 | RazorViewEmptyScaffolder 6 | root/Common/MVC/View 7 | 8 | -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/Views/Home/Add.cshtml: -------------------------------------------------------------------------------- 1 | @model Item 2 | 3 |
4 |
5 | 6 | 7 |
8 | 9 | Cancel 10 |
11 | -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model TodoList.Models.TodoListViewModel 2 | 3 | @{ 4 | ViewData["Title"] = "Home Page"; 5 | } 6 | 7 |
8 |

To Do

9 |
    10 | @foreach (var item in Model.Items) 11 | { 12 |
  • @item.Text
  • 13 | } 14 |
15 | Add 16 | 17 |
18 | -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @model ErrorViewModel 2 | @{ 3 | ViewData["Title"] = "Error"; 4 | } 5 | 6 |

Error.

7 |

An error occurred while processing your request.

8 | 9 | @if (Model.ShowRequestId) 10 | { 11 |

12 | Request ID: @Model.RequestId 13 |

14 | } 15 | 16 |

Development Mode

17 |

18 | Swapping to Development environment will display more detailed information about the error that occurred. 19 |

20 |

21 | The Development environment shouldn't be enabled for deployed applications. 22 | It can result in displaying sensitive information from exceptions to end users. 23 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development 24 | and restarting the app. 25 |

26 | -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewData["Title"] - TodoList 7 | 8 | 9 | 10 | 11 | 12 |
13 | 32 |
33 |
34 |
35 | @RenderBody() 36 |
37 |
38 | 39 |
40 |
41 | © 2024 - TodoList - Privacy 42 |
43 |
44 | 45 | 46 | 47 | @await RenderSectionAsync("Scripts", required: false) 48 | 49 | 50 | -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/Views/Shared/_Layout.cshtml.css: -------------------------------------------------------------------------------- 1 | /* Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | for details on configuring this project to bundle and minify static web assets. */ 3 | 4 | a.navbar-brand { 5 | white-space: normal; 6 | text-align: center; 7 | word-break: break-all; 8 | } 9 | 10 | a { 11 | color: #0077cc; 12 | } 13 | 14 | .btn-primary { 15 | color: #fff; 16 | background-color: #1b6ec2; 17 | border-color: #1861ac; 18 | } 19 | 20 | .nav-pills .nav-link.active, .nav-pills .show > .nav-link { 21 | color: #fff; 22 | background-color: #1b6ec2; 23 | border-color: #1861ac; 24 | } 25 | 26 | .border-top { 27 | border-top: 1px solid #e5e5e5; 28 | } 29 | .border-bottom { 30 | border-bottom: 1px solid #e5e5e5; 31 | } 32 | 33 | .box-shadow { 34 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05); 35 | } 36 | 37 | button.accept-policy { 38 | font-size: 1rem; 39 | line-height: inherit; 40 | } 41 | 42 | .footer { 43 | position: absolute; 44 | bottom: 0; 45 | width: 100%; 46 | white-space: nowrap; 47 | line-height: 60px; 48 | } 49 | -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/Views/Shared/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using TodoList 2 | @using TodoList.Models 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-size: 14px; 3 | } 4 | 5 | @media (min-width: 768px) { 6 | html { 7 | font-size: 16px; 8 | } 9 | } 10 | 11 | .btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus { 12 | box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb; 13 | } 14 | 15 | html { 16 | position: relative; 17 | min-height: 100%; 18 | } 19 | 20 | body { 21 | margin-bottom: 60px; 22 | } -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daohainam/lets-learn-aspnet/ee9bcdf96c487cd2a270c660f5ff468f776241a0/Projects/TodoList/TodoList/wwwroot/favicon.ico -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/wwwroot/js/site.js: -------------------------------------------------------------------------------- 1 | // Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | // for details on configuring this project to bundle and minify static web assets. 3 | 4 | // Write your JavaScript code. 5 | -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/wwwroot/lib/bootstrap/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2021 Twitter, Inc. 4 | Copyright (c) 2011-2021 The Bootstrap Authors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) .NET Foundation and Contributors 4 | 5 | All rights reserved. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/wwwroot/lib/jquery-validation/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright Jörn Zaefferer 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Projects/TodoList/TodoList/wwwroot/lib/jquery/LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Copyright OpenJS Foundation and other contributors, https://openjsf.org/ 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Projects/TodoList/UseCases/IToDoItemRepository.cs: -------------------------------------------------------------------------------- 1 | using Entities; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace UseCases 9 | { 10 | public interface IToDoItemRepository 11 | { 12 | void Add(TodoItem item); 13 | void Delete(int id); 14 | TodoItem? GetById(int id); 15 | IEnumerable GetItems(); 16 | void Update(TodoItem item); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Projects/TodoList/UseCases/TodoListManager.cs: -------------------------------------------------------------------------------- 1 | using Entities; 2 | 3 | namespace UseCases 4 | { 5 | public class TodoListManager(IToDoItemRepository repository) 6 | { 7 | private readonly IToDoItemRepository repository = repository; 8 | 9 | public IEnumerable GetTodoItems() 10 | { 11 | return repository.GetItems(); 12 | } 13 | 14 | public void AddTodoItem(TodoItem item) 15 | { 16 | repository.Add(item); 17 | } 18 | 19 | public void MarkComplete(int id) 20 | { 21 | var item = repository.GetById(id); 22 | if (item != null) 23 | { 24 | item.IsCompleted = true; 25 | repository.Update(item); 26 | } 27 | } 28 | 29 | public void Delete(int id) 30 | { 31 | repository.Delete(id); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Projects/TodoList/UseCases/UseCases.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Khóa học ASP.NET, Web API 2 | (đã hoàn thành) 3 | 4 | Nội dung các video của khóa học có thể xem tại đây: https://www.youtube.com/playlist?list=PLRLJQuuRRcFnwlQxGeVSVv-z_5tFwAh0j 5 | 6 | ## Mục tiêu 7 | - Hiểu rõ cách vận hành của một phần mềm ASP.NET. 8 | - Biết cách đọc tài liệu và tự học các công nghệ khác trên .NET. 9 | - Có khả năng tham gia vào các dự án thực tế sử dụng ASP.NET. 10 | - Biết cách tổ chức một dự án nhỏ với các công nghệ đã học trong khóa học. 11 | 12 | ## Tổng quan chương trình 13 | Khóa học sẽ bao gồm các nhóm nội dung cơ bản sau: 14 | - Căn bản về ASP.NET MVC, Web API. 15 | - Thiết kế và triển khai ứng dụng ASP.NET. 16 | - Bài tập áp dụng các kiến thức đã học, đồng thời kết hợp tìm hiểu về các design pattern. 17 | - Tối ưu và best practices với ứng dụng web. 18 | 19 | ## Nội dung 20 | 21 | - Khởi tạo một dự án ASP.NET MVC và tìm hiểu các thành phần. 22 | - Tìm hiểu Controller và Action method. 23 | - Các Attribute trong ASP.NET. 24 | - Routing. 25 | - Bài tập: Viết chương trình To Do List. 26 | - Sử dụng đối tượng HttpContext. 27 | - Static files. 28 | - Gửi dữ liệu lên server với POST (và model binding). 29 | - Session. 30 | - Configuration trong ASP.NET. 31 | - Options pattern. 32 | - Giới thiệu về middleware. 33 | - Middleware: Https redirection. 34 | - Middleware: Authentication và Authorization. 35 | - Middleware: CORS. 36 | - Middleware: Rate Limit. 37 | - Middleware: Response Caching. 38 | - Caching trong ASP.NET. 39 | - Web API: Khởi tạo một dự án Web API. 40 | - Web API: Các Attribute thường dùng trong Web API. 41 | - Web API: Các kiểu dữ liệu trả về từ một Web API. 42 | - Web API: Các quy ước được dùng khi viết API. 43 | - Web API: Minimal API. 44 | - Web API: Swagger/Open API. 45 | - Integration testing với ASP.NET 46 | - Tạo một Docker image 47 | - Sử dụng NGINX làm reversed proxy. 48 | 49 | --------------------------------------------------------------------------------