├── .gitattributes ├── .gitignore ├── LICENSE.txt ├── README.md ├── artifacts └── .gitkeep ├── global.json ├── install.ps1 ├── pack.ps1 ├── template ├── .template.config │ └── template.json ├── BlazorWithIdentity.Client │ ├── App.razor │ ├── BlazorWithIdentity.Client.csproj │ ├── Pages │ │ ├── Counter.razor │ │ ├── FetchData.razor │ │ ├── Index.razor │ │ ├── Login.razor │ │ └── Register.razor │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Services │ │ ├── Contracts │ │ │ └── IAuthorizeApi.cs │ │ └── Implementations │ │ │ ├── AuthorizeApi.cs │ │ │ └── IdentityAuthenticationStateProvider.cs │ ├── Shared │ │ ├── LoginLayout.razor │ │ ├── MainLayout.razor │ │ ├── MainLayout.razor.css │ │ ├── NavMenu.razor │ │ ├── NavMenu.razor.css │ │ ├── RedirectToLogin.razor │ │ └── SurveyPrompt.razor │ ├── _Imports.razor │ └── wwwroot │ │ ├── css │ │ ├── app.css │ │ ├── bootstrap │ │ │ ├── bootstrap.min.css │ │ │ └── bootstrap.min.css.map │ │ └── open-iconic │ │ │ ├── FONT-LICENSE │ │ │ ├── ICON-LICENSE │ │ │ ├── README.md │ │ │ └── font │ │ │ ├── css │ │ │ └── open-iconic-bootstrap.min.css │ │ │ └── fonts │ │ │ ├── open-iconic.eot │ │ │ ├── open-iconic.otf │ │ │ ├── open-iconic.svg │ │ │ ├── open-iconic.ttf │ │ │ └── open-iconic.woff │ │ ├── favicon.png │ │ ├── icon-192.png │ │ └── index.html ├── BlazorWithIdentity.Server │ ├── BlazorWithIdentity.Server.csproj │ ├── Controllers │ │ ├── AuthorizeController.cs │ │ └── SampleDataController.cs │ ├── Data │ │ └── ApplicationDbContext.cs │ ├── Migrations │ │ ├── 20190502083628_Init.Designer.cs │ │ ├── 20190502083628_Init.cs │ │ └── ApplicationDbContextModelSnapshot.cs │ ├── Models │ │ └── ApplicationUser.cs │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── appsettings.Development.json │ └── appsettings.json ├── BlazorWithIdentity.Shared │ ├── BlazorWithIdentity.Shared.csproj │ ├── LoginParameters.cs │ ├── RegisterParameters.cs │ ├── UserInfo.cs │ └── WeatherForecast.cs └── BlazorWithIdentity.sln ├── templatepack.csproj └── uninstall.ps1 /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | [Aa][Rr][Mm]/ 24 | [Aa][Rr][Mm]64/ 25 | bld/ 26 | [Bb]in/ 27 | [Oo]bj/ 28 | [Ll]og/ 29 | 30 | # Visual Studio 2015/2017 cache/options directory 31 | .vs/ 32 | # Uncomment if you have tasks that create the project's static files in wwwroot 33 | #wwwroot/ 34 | 35 | # Visual Studio 2017 auto generated files 36 | Generated\ Files/ 37 | 38 | # MSTest test Results 39 | [Tt]est[Rr]esult*/ 40 | [Bb]uild[Ll]og.* 41 | 42 | # NUNIT 43 | *.VisualState.xml 44 | TestResult.xml 45 | 46 | # Build Results of an ATL Project 47 | [Dd]ebugPS/ 48 | [Rr]eleasePS/ 49 | dlldata.c 50 | 51 | # Benchmark Results 52 | BenchmarkDotNet.Artifacts/ 53 | 54 | # .NET Core 55 | project.lock.json 56 | project.fragment.lock.json 57 | 58 | # StyleCop 59 | StyleCopReport.xml 60 | 61 | # Files built by Visual Studio 62 | *_i.c 63 | *_p.c 64 | *_h.h 65 | *.ilk 66 | *.meta 67 | *.obj 68 | *.iobj 69 | *.pch 70 | *.pdb 71 | *.ipdb 72 | *.pgc 73 | *.pgd 74 | *.rsp 75 | *.sbr 76 | *.tlb 77 | *.tli 78 | *.tlh 79 | *.tmp 80 | *.tmp_proj 81 | *_wpftmp.csproj 82 | *.log 83 | *.vspscc 84 | *.vssscc 85 | .builds 86 | *.pidb 87 | *.svclog 88 | *.scc 89 | 90 | # Chutzpah Test files 91 | _Chutzpah* 92 | 93 | # Visual C++ cache files 94 | ipch/ 95 | *.aps 96 | *.ncb 97 | *.opendb 98 | *.opensdf 99 | *.sdf 100 | *.cachefile 101 | *.VC.db 102 | *.VC.VC.opendb 103 | 104 | # Visual Studio profiler 105 | *.psess 106 | *.vsp 107 | *.vspx 108 | *.sap 109 | 110 | # Visual Studio Trace Files 111 | *.e2e 112 | 113 | # TFS 2012 Local Workspace 114 | $tf/ 115 | 116 | # Guidance Automation Toolkit 117 | *.gpState 118 | 119 | # ReSharper is a .NET coding add-in 120 | _ReSharper*/ 121 | *.[Rr]e[Ss]harper 122 | *.DotSettings.user 123 | 124 | # JustCode is a .NET coding add-in 125 | .JustCode 126 | 127 | # TeamCity is a build add-in 128 | _TeamCity* 129 | 130 | # DotCover is a Code Coverage Tool 131 | *.dotCover 132 | 133 | # AxoCover is a Code Coverage Tool 134 | .axoCover/* 135 | !.axoCover/settings.json 136 | 137 | # Visual Studio code coverage results 138 | *.coverage 139 | *.coveragexml 140 | 141 | # NCrunch 142 | _NCrunch_* 143 | .*crunch*.local.xml 144 | nCrunchTemp_* 145 | 146 | # MightyMoose 147 | *.mm.* 148 | AutoTest.Net/ 149 | 150 | # Web workbench (sass) 151 | .sass-cache/ 152 | 153 | # Installshield output folder 154 | [Ee]xpress/ 155 | 156 | # DocProject is a documentation generator add-in 157 | DocProject/buildhelp/ 158 | DocProject/Help/*.HxT 159 | DocProject/Help/*.HxC 160 | DocProject/Help/*.hhc 161 | DocProject/Help/*.hhk 162 | DocProject/Help/*.hhp 163 | DocProject/Help/Html2 164 | DocProject/Help/html 165 | 166 | # Click-Once directory 167 | publish/ 168 | 169 | # Publish Web Output 170 | *.[Pp]ublish.xml 171 | *.azurePubxml 172 | # Note: Comment the next line if you want to checkin your web deploy settings, 173 | # but database connection strings (with potential passwords) will be unencrypted 174 | *.pubxml 175 | *.publishproj 176 | 177 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 178 | # checkin your Azure Web App publish settings, but sensitive information contained 179 | # in these scripts will be unencrypted 180 | PublishScripts/ 181 | 182 | # NuGet Packages 183 | *.nupkg 184 | # The packages folder can be ignored because of Package Restore 185 | **/[Pp]ackages/* 186 | # except build/, which is used as an MSBuild target. 187 | !**/[Pp]ackages/build/ 188 | # Uncomment if necessary however generally it will be regenerated when needed 189 | #!**/[Pp]ackages/repositories.config 190 | # NuGet v3's project.json files produces more ignorable files 191 | *.nuget.props 192 | *.nuget.targets 193 | 194 | # Microsoft Azure Build Output 195 | csx/ 196 | *.build.csdef 197 | 198 | # Microsoft Azure Emulator 199 | ecf/ 200 | rcf/ 201 | 202 | # Windows Store app package directories and files 203 | AppPackages/ 204 | BundleArtifacts/ 205 | Package.StoreAssociation.xml 206 | _pkginfo.txt 207 | *.appx 208 | 209 | # Visual Studio cache files 210 | # files ending in .cache can be ignored 211 | *.[Cc]ache 212 | # but keep track of directories ending in .cache 213 | !?*.[Cc]ache/ 214 | 215 | # Others 216 | ClientBin/ 217 | ~$* 218 | *~ 219 | *.dbmdl 220 | *.dbproj.schemaview 221 | *.jfm 222 | *.pfx 223 | *.publishsettings 224 | orleans.codegen.cs 225 | 226 | # Including strong name files can present a security risk 227 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 228 | #*.snk 229 | 230 | # Since there are multiple workflows, uncomment next line to ignore bower_components 231 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 232 | #bower_components/ 233 | 234 | # RIA/Silverlight projects 235 | Generated_Code/ 236 | 237 | # Backup & report files from converting an old project file 238 | # to a newer Visual Studio version. Backup files are not needed, 239 | # because we have git ;-) 240 | _UpgradeReport_Files/ 241 | Backup*/ 242 | UpgradeLog*.XML 243 | UpgradeLog*.htm 244 | ServiceFabricBackup/ 245 | *.rptproj.bak 246 | 247 | # SQL Server files 248 | *.mdf 249 | *.ldf 250 | *.ndf 251 | 252 | # Business Intelligence projects 253 | *.rdl.data 254 | *.bim.layout 255 | *.bim_*.settings 256 | *.rptproj.rsuser 257 | *- Backup*.rdl 258 | 259 | # Microsoft Fakes 260 | FakesAssemblies/ 261 | 262 | # GhostDoc plugin setting file 263 | *.GhostDoc.xml 264 | 265 | # Node.js Tools for Visual Studio 266 | .ntvs_analysis.dat 267 | node_modules/ 268 | 269 | # Visual Studio 6 build log 270 | *.plg 271 | 272 | # Visual Studio 6 workspace options file 273 | *.opt 274 | 275 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 276 | *.vbw 277 | 278 | # Visual Studio LightSwitch build output 279 | **/*.HTMLClient/GeneratedArtifacts 280 | **/*.DesktopClient/GeneratedArtifacts 281 | **/*.DesktopClient/ModelManifest.xml 282 | **/*.Server/GeneratedArtifacts 283 | **/*.Server/ModelManifest.xml 284 | _Pvt_Extensions 285 | 286 | # Paket dependency manager 287 | .paket/paket.exe 288 | paket-files/ 289 | 290 | # FAKE - F# Make 291 | .fake/ 292 | 293 | # JetBrains Rider 294 | .idea/ 295 | *.sln.iml 296 | 297 | # CodeRush personal settings 298 | .cr/personal 299 | 300 | # Python Tools for Visual Studio (PTVS) 301 | __pycache__/ 302 | *.pyc 303 | 304 | # Cake - Uncomment if you are using it 305 | # tools/** 306 | # !tools/packages.config 307 | 308 | # Tabs Studio 309 | *.tss 310 | 311 | # Telerik's JustMock configuration file 312 | *.jmconfig 313 | 314 | # BizTalk build output 315 | *.btp.cs 316 | *.btm.cs 317 | *.odx.cs 318 | *.xsd.cs 319 | 320 | # OpenCover UI analysis results 321 | OpenCover/ 322 | 323 | # Azure Stream Analytics local run output 324 | ASALocalRun/ 325 | 326 | # MSBuild Binary and Structured Log 327 | *.binlog 328 | 329 | # NVidia Nsight GPU debugger configuration file 330 | *.nvuser 331 | 332 | # MFractors (Xamarin productivity tool) working folder 333 | .mfractor/ 334 | 335 | # Local History for Visual Studio 336 | .localhistory/ 337 | 338 | # BeatPulse healthcheck temp database 339 | healthchecksdb 340 | **/data.db 341 | /template/BlazorWithIdentity.Server/data.db-shm 342 | /template/BlazorWithIdentity.Server/data.db-wal 343 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 stavroskasidis 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Blazor with Identity 2 | 3 | [![Build status](https://dev.azure.com/stavros-kasidis/Blazor%20With%20Identity/_apis/build/status/Blazor%20With%20Identity-CI)](https://dev.azure.com/stavros-kasidis/Blazor%20With%20Identity/_build/latest?definitionId=18) [![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/BlazorWithIdentity.Template.svg?logo=nuget)](https://www.nuget.org/packages/BlazorWithIdentity.Template) [![Nuget](https://img.shields.io/nuget/dt/BlazorWithIdentity.Template.svg?logo=nuget)](https://www.nuget.org/packages/BlazorWithIdentity.Template) [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=7CRGWPYB5AKJQ¤cy_code=EUR&source=url) 4 | 5 | 6 | A project template for a blazor wasm hosted app using cookie based authentication with ef core identity 7 | 8 | ## Using the template 9 | 1. Install the template 10 | ``` 11 | dotnet new --install BlazorWithIdentity.Template 12 | ``` 13 | 2. Create a new project 14 | ``` 15 | dotnet new blazorwithidentity -o MyBlazorApp 16 | ``` 17 | 18 | ## How to run 19 | 1. Install [**the latest dotnet sdk**](https://dotnet.microsoft.com/download) and the latest [**Visual Studio**](https://visualstudio.microsoft.com/vs/). 20 | 2. Clone or download. 21 | 3. Open the solution in the template folder and press F5. 22 | 4. Create a user using the `Create Account` button in the login page or login if you have already created a user. 23 | 24 | ## Live demo 25 | https://blazorwithidentity.azurewebsites.net/ 26 | -------------------------------------------------------------------------------- /artifacts/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stavroskasidis/BlazorWithIdentity/f26d28fce6c6a52126634ba8131054c3ee77ffd0/artifacts/.gitkeep -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "7.0.100" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /install.ps1: -------------------------------------------------------------------------------- 1 | dotnet new -u BlazorWithIdentity.Template 2 | dotnet new -i artifacts\BlazorWithIdentity.Template.* -------------------------------------------------------------------------------- /pack.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [string] $VersionSuffix 3 | ) 4 | Push-Location $PSScriptRoot 5 | 6 | function Write-Message{ 7 | param([string]$message) 8 | Write-Host 9 | Write-Host $message 10 | Write-Host 11 | } 12 | function Confirm-PreviousCommand { 13 | param([string]$errorMessage) 14 | if ( $LASTEXITCODE -ne 0) { 15 | if( $errorMessage) { 16 | Write-Message $errorMessage 17 | } 18 | exit $LASTEXITCODE 19 | } 20 | } 21 | 22 | function Confirm-Process { 23 | param ([System.Diagnostics.Process]$process,[string]$errorMessage) 24 | $process.WaitForExit() 25 | if($process.ExitCode -ne 0){ 26 | Write-Host $process.ExitCode 27 | if( $errorMessage) { 28 | Write-Message $errorMessage 29 | } 30 | exit $process.ExitCode 31 | } 32 | } 33 | 34 | Write-Host "Parameters" 35 | Write-Host "==========" 36 | Write-Host "Version suffix: $VersionSuffix" 37 | 38 | # Check prerequisites 39 | $proc = Start-Process "dotnet" -ArgumentList "--version" -PassThru 40 | Confirm-Process $proc "Could not find dotnet sdk, please install and run again ..." 41 | 42 | Write-Message "Cleaning artifacts folder" 43 | Remove-Item -Path artifacts/*.nupkg -Recurse 44 | 45 | Write-Message "Packing ..." 46 | dotnet pack templatepack.csproj -c Release -o artifacts /p:VersionSuffix="$VersionSuffix" 47 | Confirm-PreviousCommand 48 | 49 | Write-Message "Pack completed successfully" -------------------------------------------------------------------------------- /template/.template.config/template.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/template", 3 | "author": "Stavros Kasidis (AkiraGTX)", 4 | "name": "Blazor With Identity", 5 | "identity": "blazor.withidentity", 6 | "groupIdentity":"blazor", 7 | "shortName": "blazorwithidentity", 8 | "classifications": [ "Web", "Blazor", "WebAssembly" ], 9 | "tags": { 10 | "language": "C#", 11 | "type":"project" 12 | }, 13 | "sourceName": "BlazorWithIdentity", 14 | "preferNameDirectory": true 15 | } -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/App.razor: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @if (context.User.Identity?.IsAuthenticated != true) 7 | { 8 | 9 | } 10 | else 11 | { 12 |

You are not authorized to access this resource.

13 | } 14 |
15 |
16 | 17 |
18 | 19 | Not found 20 | 21 |

Sorry, there's nothing at this address.

22 |
23 |
24 |
25 |
26 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/BlazorWithIdentity.Client.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/Pages/Counter.razor: -------------------------------------------------------------------------------- 1 | @page "/counter" 2 | @attribute [Authorize] 3 | 4 | Counter 5 | 6 |

Counter

7 | 8 |

Current count: @currentCount

9 | 10 | 11 | 12 | @code { 13 | private int currentCount = 0; 14 | 15 | private void IncrementCount() 16 | { 17 | currentCount++; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/Pages/FetchData.razor: -------------------------------------------------------------------------------- 1 | @page "/fetchdata" 2 | @attribute [Authorize] 3 | @using BlazorWithIdentity.Shared 4 | @inject HttpClient Http 5 | 6 | Weather forecast 7 | 8 |

Weather forecast

9 | 10 |

This component demonstrates fetching data from the server.

11 | 12 | @if (forecasts == null) 13 | { 14 |

Loading...

15 | } 16 | else 17 | { 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | @foreach (var forecast in forecasts) 29 | { 30 | 31 | 32 | 33 | 34 | 35 | 36 | } 37 | 38 |
DateTemp. (C)Temp. (F)Summary
@forecast.Date.ToShortDateString()@forecast.TemperatureC@forecast.TemperatureF@forecast.Summary
39 | } 40 | 41 | @code { 42 | private WeatherForecast[]? forecasts; 43 | 44 | protected override async Task OnInitializedAsync() 45 | { 46 | forecasts = await Http.GetFromJsonAsync("api/SampleData/WeatherForecasts"); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/Pages/Index.razor: -------------------------------------------------------------------------------- 1 | @page "/" 2 | @attribute [Authorize] 3 | 4 | Index 5 | 6 | 7 | 8 |

Hello @context.User.Identity.Name !!

9 | 10 | Welcome to your new app. 11 | 12 | 13 |
14 | 15 |

Loading ...

16 |
17 |
-------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/Pages/Login.razor: -------------------------------------------------------------------------------- 1 | @page "/login" 2 | @layout LoginLayout 3 | @inject NavigationManager navigationManager 4 | @inject IdentityAuthenticationStateProvider authStateProvider 5 | 6 | Login 7 | 8 |

9 | Blazor with Identity Sample 10 |

11 | 12 |
13 |
14 |
15 |
16 |
17 |

Login

18 |
19 |
20 | 52 |
53 |
54 |
55 |
56 |
57 | 58 | @code { 59 | LoginParameters loginParameters { get; set; } = new LoginParameters(); 60 | string error { get; set; } 61 | 62 | async Task OnSubmit() 63 | { 64 | error = null; 65 | try 66 | { 67 | await authStateProvider.Login(loginParameters); 68 | navigationManager.NavigateTo(""); 69 | } 70 | catch (Exception ex) 71 | { 72 | error = ex.Message; 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/Pages/Register.razor: -------------------------------------------------------------------------------- 1 | @page "/register" 2 | @layout LoginLayout 3 | @inject NavigationManager navigationManager 4 | @inject IdentityAuthenticationStateProvider authStateProvider 5 | 6 | Register 7 | 8 |

9 | Blazor with Identity Sample 10 |

11 | 12 |
13 |
14 |
15 |
16 |
17 |

Create Account

18 |
19 |
20 | 51 |
52 |
53 |
54 |
55 |
56 | 57 | @code { 58 | 59 | RegisterParameters registerParameters { get; set; } = new RegisterParameters(); 60 | string error { get; set; } 61 | 62 | async Task OnSubmit() 63 | { 64 | error = null; 65 | try 66 | { 67 | await authStateProvider.Register(registerParameters); 68 | navigationManager.NavigateTo(""); 69 | } 70 | catch (Exception ex) 71 | { 72 | error = ex.Message; 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/Program.cs: -------------------------------------------------------------------------------- 1 | using BlazorWithIdentity.Client; 2 | using BlazorWithIdentity.Client.Services.Contracts; 3 | using BlazorWithIdentity.Client.Services.Implementations; 4 | using BlazorWithIdentity.Client.States; 5 | using Microsoft.AspNetCore.Components.Web; 6 | using Microsoft.AspNetCore.Components.Authorization; 7 | using Microsoft.AspNetCore.Components.WebAssembly.Hosting; 8 | 9 | var builder = WebAssemblyHostBuilder.CreateDefault(args); 10 | builder.RootComponents.Add("#app"); 11 | builder.RootComponents.Add("head::after"); 12 | 13 | builder.Services.AddOptions(); 14 | builder.Services.AddAuthorizationCore(); 15 | builder.Services.AddScoped(); 16 | builder.Services.AddScoped(s => s.GetRequiredService()); 17 | builder.Services.AddScoped(); 18 | builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); 19 | 20 | await builder.Build().RunAsync(); -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:53415", 7 | "sslPort": 44370 8 | } 9 | }, 10 | "profiles": { 11 | "BlazorWithIdentity": { 12 | "commandName": "Project", 13 | "dotnetRunMessages": "true", 14 | "launchBrowser": true, 15 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 16 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 17 | "environmentVariables": { 18 | "ASPNETCORE_ENVIRONMENT": "Development" 19 | } 20 | }, 21 | "IIS Express": { 22 | "commandName": "IISExpress", 23 | "launchBrowser": true, 24 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 25 | "environmentVariables": { 26 | "ASPNETCORE_ENVIRONMENT": "Development" 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/Services/Contracts/IAuthorizeApi.cs: -------------------------------------------------------------------------------- 1 | using BlazorWithIdentity.Shared; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace BlazorWithIdentity.Client.Services.Contracts 8 | { 9 | public interface IAuthorizeApi 10 | { 11 | Task Login(LoginParameters loginParameters); 12 | Task Register(RegisterParameters registerParameters); 13 | Task Logout(); 14 | Task GetUserInfo(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/Services/Implementations/AuthorizeApi.cs: -------------------------------------------------------------------------------- 1 | using BlazorWithIdentity.Client.Services.Contracts; 2 | using BlazorWithIdentity.Shared; 3 | using Microsoft.AspNetCore.Components; 4 | using Microsoft.JSInterop; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Net.Http; 9 | using System.Net.Http.Json; 10 | using System.Text; 11 | using System.Text.Json; 12 | using System.Text.Json.Serialization; 13 | using System.Threading.Tasks; 14 | 15 | namespace BlazorWithIdentity.Client.Services.Implementations 16 | { 17 | public class AuthorizeApi : IAuthorizeApi 18 | { 19 | private readonly HttpClient _httpClient; 20 | 21 | public AuthorizeApi(HttpClient httpClient) 22 | { 23 | _httpClient = httpClient; 24 | } 25 | 26 | public async Task Login(LoginParameters loginParameters) 27 | { 28 | //var stringContent = new StringContent(JsonSerializer.Serialize(loginParameters), Encoding.UTF8, "application/json"); 29 | var result = await _httpClient.PostAsJsonAsync("api/Authorize/Login", loginParameters); 30 | if (result.StatusCode == System.Net.HttpStatusCode.BadRequest) throw new Exception(await result.Content.ReadAsStringAsync()); 31 | result.EnsureSuccessStatusCode(); 32 | } 33 | 34 | public async Task Logout() 35 | { 36 | var result = await _httpClient.PostAsync("api/Authorize/Logout", null); 37 | result.EnsureSuccessStatusCode(); 38 | } 39 | 40 | public async Task Register(RegisterParameters registerParameters) 41 | { 42 | //var stringContent = new StringContent(JsonSerializer.Serialize(registerParameters), Encoding.UTF8, "application/json"); 43 | var result = await _httpClient.PostAsJsonAsync("api/Authorize/Register", registerParameters); 44 | if (result.StatusCode == System.Net.HttpStatusCode.BadRequest) throw new Exception(await result.Content.ReadAsStringAsync()); 45 | result.EnsureSuccessStatusCode(); 46 | } 47 | 48 | public async Task GetUserInfo() 49 | { 50 | var result = await _httpClient.GetFromJsonAsync("api/Authorize/UserInfo"); 51 | return result; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/Services/Implementations/IdentityAuthenticationStateProvider.cs: -------------------------------------------------------------------------------- 1 | using BlazorWithIdentity.Client.Services.Contracts; 2 | using BlazorWithIdentity.Shared; 3 | using Microsoft.AspNetCore.Components; 4 | using Microsoft.AspNetCore.Components.Authorization; 5 | using Microsoft.JSInterop; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Net; 10 | using System.Net.Http; 11 | using System.Security.Claims; 12 | using System.Threading.Tasks; 13 | 14 | namespace BlazorWithIdentity.Client.States 15 | { 16 | public class IdentityAuthenticationStateProvider : AuthenticationStateProvider 17 | { 18 | private UserInfo _userInfoCache; 19 | private readonly IAuthorizeApi _authorizeApi; 20 | 21 | public IdentityAuthenticationStateProvider(IAuthorizeApi authorizeApi) 22 | { 23 | this._authorizeApi = authorizeApi; 24 | } 25 | 26 | public async Task Login(LoginParameters loginParameters) 27 | { 28 | await _authorizeApi.Login(loginParameters); 29 | NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); 30 | } 31 | 32 | public async Task Register(RegisterParameters registerParameters) 33 | { 34 | await _authorizeApi.Register(registerParameters); 35 | NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); 36 | } 37 | 38 | public async Task Logout() 39 | { 40 | await _authorizeApi.Logout(); 41 | _userInfoCache = null; 42 | NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); 43 | } 44 | 45 | private async Task GetUserInfo() 46 | { 47 | if (_userInfoCache != null && _userInfoCache.IsAuthenticated) return _userInfoCache; 48 | _userInfoCache = await _authorizeApi.GetUserInfo(); 49 | return _userInfoCache; 50 | } 51 | 52 | public override async Task GetAuthenticationStateAsync() 53 | { 54 | var identity = new ClaimsIdentity(); 55 | try 56 | { 57 | var userInfo = await GetUserInfo(); 58 | if (userInfo.IsAuthenticated) 59 | { 60 | var claims = new[] { new Claim(ClaimTypes.Name, userInfo.UserName) }.Concat(userInfo.ExposedClaims.Select(c => new Claim(c.Key, c.Value))); 61 | identity = new ClaimsIdentity(claims, "Server authentication"); 62 | } 63 | } 64 | catch (HttpRequestException ex) 65 | { 66 | Console.WriteLine("Request failed:" + ex.ToString()); 67 | } 68 | 69 | return new AuthenticationState(new ClaimsPrincipal(identity)); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/Shared/LoginLayout.razor: -------------------------------------------------------------------------------- 1 | @inherits LayoutComponentBase 2 | 3 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/Shared/MainLayout.razor: -------------------------------------------------------------------------------- 1 | @inherits LayoutComponentBase 2 | @inject NavigationManager navigationManager 3 | @inject IdentityAuthenticationStateProvider authStateProvider 4 |
5 | 6 | 7 | @*Show the menu and the rest of the body*@ 8 | 11 | 12 |
13 |
14 | 15 |
16 | 17 |
18 | @Body 19 |
20 |
21 |
22 | 23 | @*Just render the body so that RedirectToLogin works*@ 24 | @Body 25 | 26 |
27 |
28 | 29 | 30 | @code { 31 | 32 | async Task LogoutClick() 33 | { 34 | await authStateProvider.Logout(); 35 | navigationManager.NavigateTo("/login"); 36 | } 37 | } -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/Shared/MainLayout.razor.css: -------------------------------------------------------------------------------- 1 | .page { 2 | position: relative; 3 | display: flex; 4 | flex-direction: column; 5 | } 6 | 7 | main { 8 | flex: 1; 9 | } 10 | 11 | .sidebar { 12 | background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); 13 | } 14 | 15 | .top-row { 16 | background-color: #f7f7f7; 17 | border-bottom: 1px solid #d6d5d5; 18 | justify-content: flex-end; 19 | height: 3.5rem; 20 | display: flex; 21 | align-items: center; 22 | } 23 | 24 | .top-row ::deep a, .top-row ::deep .btn-link { 25 | white-space: nowrap; 26 | margin-left: 1.5rem; 27 | text-decoration: none; 28 | } 29 | 30 | .top-row ::deep a:hover, .top-row ::deep .btn-link:hover { 31 | text-decoration: underline; 32 | } 33 | 34 | .top-row ::deep a:first-child { 35 | overflow: hidden; 36 | text-overflow: ellipsis; 37 | } 38 | 39 | @media (max-width: 640.98px) { 40 | .top-row:not(.auth) { 41 | display: none; 42 | } 43 | 44 | .top-row.auth { 45 | justify-content: space-between; 46 | } 47 | 48 | .top-row ::deep a, .top-row ::deep .btn-link { 49 | margin-left: 0; 50 | } 51 | } 52 | 53 | @media (min-width: 641px) { 54 | .page { 55 | flex-direction: row; 56 | } 57 | 58 | .sidebar { 59 | width: 250px; 60 | height: 100vh; 61 | position: sticky; 62 | top: 0; 63 | } 64 | 65 | .top-row { 66 | position: sticky; 67 | top: 0; 68 | z-index: 1; 69 | } 70 | 71 | .top-row.auth ::deep a:first-child { 72 | flex: 1; 73 | text-align: right; 74 | width: 0; 75 | } 76 | 77 | .top-row, article { 78 | padding-left: 2rem !important; 79 | padding-right: 1.5rem !important; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/Shared/NavMenu.razor: -------------------------------------------------------------------------------- 1 |  9 | 10 | 29 | 30 | @code { 31 | private bool collapseNavMenu = true; 32 | 33 | private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null; 34 | 35 | private void ToggleNavMenu() 36 | { 37 | collapseNavMenu = !collapseNavMenu; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/Shared/NavMenu.razor.css: -------------------------------------------------------------------------------- 1 | .navbar-toggler { 2 | background-color: rgba(255, 255, 255, 0.1); 3 | } 4 | 5 | .top-row { 6 | height: 3.5rem; 7 | background-color: rgba(0,0,0,0.4); 8 | } 9 | 10 | .navbar-brand { 11 | font-size: 1.1rem; 12 | } 13 | 14 | .oi { 15 | width: 2rem; 16 | font-size: 1.1rem; 17 | vertical-align: text-top; 18 | top: -2px; 19 | } 20 | 21 | .nav-item { 22 | font-size: 0.9rem; 23 | padding-bottom: 0.5rem; 24 | } 25 | 26 | .nav-item:first-of-type { 27 | padding-top: 1rem; 28 | } 29 | 30 | .nav-item:last-of-type { 31 | padding-bottom: 1rem; 32 | } 33 | 34 | .nav-item ::deep a { 35 | color: #d7d7d7; 36 | border-radius: 4px; 37 | height: 3rem; 38 | display: flex; 39 | align-items: center; 40 | line-height: 3rem; 41 | } 42 | 43 | .nav-item ::deep a.active { 44 | background-color: rgba(255,255,255,0.25); 45 | color: white; 46 | } 47 | 48 | .nav-item ::deep a:hover { 49 | background-color: rgba(255,255,255,0.1); 50 | color: white; 51 | } 52 | 53 | @media (min-width: 641px) { 54 | .navbar-toggler { 55 | display: none; 56 | } 57 | 58 | .collapse { 59 | /* Never collapse the sidebar for wide screens */ 60 | display: block; 61 | } 62 | 63 | .nav-scrollable { 64 | /* Allow sidebar to scroll for tall menus */ 65 | height: calc(100vh - 3.5rem); 66 | overflow-y: auto; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/Shared/RedirectToLogin.razor: -------------------------------------------------------------------------------- 1 | @inject NavigationManager navigationManager 2 |
Redirecting...
3 | @code{ 4 | 5 | protected override void OnInitialized() 6 | { 7 | navigationManager.NavigateTo("/login"); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/Shared/SurveyPrompt.razor: -------------------------------------------------------------------------------- 1 | 
2 | 3 | @Title 4 | 5 | 6 | Please take our 7 | brief survey 8 | 9 | and tell us what you think. 10 |
11 | 12 | @code { 13 | // Demonstrates how a parent component can supply parameters 14 | [Parameter] 15 | public string? Title { get; set; } 16 | } 17 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using Microsoft.AspNetCore.Components.Forms 3 | @using Microsoft.AspNetCore.Components.Routing 4 | @using Microsoft.AspNetCore.Components.Web 5 | @using Microsoft.AspNetCore.Authorization.Infrastructure 6 | @using Microsoft.AspNetCore.Components.Authorization 7 | @using Microsoft.AspNetCore.Authorization 8 | @using Microsoft.JSInterop 9 | @using BlazorWithIdentity.Shared 10 | @using BlazorWithIdentity.Client 11 | @using BlazorWithIdentity.Client.Shared 12 | @using BlazorWithIdentity.Client.Services.Contracts 13 | @using BlazorWithIdentity.Client.Services.Implementations 14 | @using BlazorWithIdentity.Client.States 15 | @using System.Security.Claims 16 | @using System.Net.Http.Json -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/wwwroot/css/app.css: -------------------------------------------------------------------------------- 1 | @import url('open-iconic/font/css/open-iconic-bootstrap.min.css'); 2 | 3 | html, body { 4 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 5 | } 6 | 7 | h1:focus { 8 | outline: none; 9 | } 10 | 11 | a, .btn-link { 12 | color: #0071c1; 13 | } 14 | 15 | .btn-primary { 16 | color: #fff; 17 | background-color: #1b6ec2; 18 | border-color: #1861ac; 19 | } 20 | 21 | .btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus { 22 | box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb; 23 | } 24 | 25 | .content { 26 | padding-top: 1.1rem; 27 | } 28 | 29 | .valid.modified:not([type=checkbox]) { 30 | outline: 1px solid #26b050; 31 | } 32 | 33 | .invalid { 34 | outline: 1px solid red; 35 | } 36 | 37 | .validation-message { 38 | color: red; 39 | } 40 | 41 | #blazor-error-ui { 42 | background: lightyellow; 43 | bottom: 0; 44 | box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); 45 | display: none; 46 | left: 0; 47 | padding: 0.6rem 1.25rem 0.7rem 1.25rem; 48 | position: fixed; 49 | width: 100%; 50 | z-index: 1000; 51 | } 52 | 53 | #blazor-error-ui .dismiss { 54 | cursor: pointer; 55 | position: absolute; 56 | right: 0.75rem; 57 | top: 0.5rem; 58 | } 59 | 60 | .blazor-error-boundary { 61 | background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121; 62 | padding: 1rem 1rem 1rem 3.7rem; 63 | color: white; 64 | } 65 | 66 | .blazor-error-boundary::after { 67 | content: "An error has occurred." 68 | } 69 | 70 | .loading-progress { 71 | position: relative; 72 | display: block; 73 | width: 8rem; 74 | height: 8rem; 75 | margin: 20vh auto 1rem auto; 76 | } 77 | 78 | .loading-progress circle { 79 | fill: none; 80 | stroke: #e0e0e0; 81 | stroke-width: 0.6rem; 82 | transform-origin: 50% 50%; 83 | transform: rotate(-90deg); 84 | } 85 | 86 | .loading-progress circle:last-child { 87 | stroke: #1b6ec2; 88 | stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%; 89 | transition: stroke-dasharray 0.05s ease-in-out; 90 | } 91 | 92 | .loading-progress-text { 93 | position: absolute; 94 | text-align: center; 95 | font-weight: bold; 96 | inset: calc(20vh + 3.25rem) 0 auto 0.2rem; 97 | } 98 | 99 | .loading-progress-text:after { 100 | content: var(--blazor-load-percentage-text, "Loading"); 101 | } 102 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/wwwroot/css/open-iconic/FONT-LICENSE: -------------------------------------------------------------------------------- 1 | SIL OPEN FONT LICENSE Version 1.1 2 | 3 | Copyright (c) 2014 Waybury 4 | 5 | PREAMBLE 6 | The goals of the Open Font License (OFL) are to stimulate worldwide 7 | development of collaborative font projects, to support the font creation 8 | efforts of academic and linguistic communities, and to provide a free and 9 | open framework in which fonts may be shared and improved in partnership 10 | with others. 11 | 12 | The OFL allows the licensed fonts to be used, studied, modified and 13 | redistributed freely as long as they are not sold by themselves. The 14 | fonts, including any derivative works, can be bundled, embedded, 15 | redistributed and/or sold with any software provided that any reserved 16 | names are not used by derivative works. The fonts and derivatives, 17 | however, cannot be released under any other type of license. The 18 | requirement for fonts to remain under this license does not apply 19 | to any document created using the fonts or their derivatives. 20 | 21 | DEFINITIONS 22 | "Font Software" refers to the set of files released by the Copyright 23 | Holder(s) under this license and clearly marked as such. This may 24 | include source files, build scripts and documentation. 25 | 26 | "Reserved Font Name" refers to any names specified as such after the 27 | copyright statement(s). 28 | 29 | "Original Version" refers to the collection of Font Software components as 30 | distributed by the Copyright Holder(s). 31 | 32 | "Modified Version" refers to any derivative made by adding to, deleting, 33 | or substituting -- in part or in whole -- any of the components of the 34 | Original Version, by changing formats or by porting the Font Software to a 35 | new environment. 36 | 37 | "Author" refers to any designer, engineer, programmer, technical 38 | writer or other person who contributed to the Font Software. 39 | 40 | PERMISSION & CONDITIONS 41 | Permission is hereby granted, free of charge, to any person obtaining 42 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 43 | redistribute, and sell modified and unmodified copies of the Font 44 | Software, subject to the following conditions: 45 | 46 | 1) Neither the Font Software nor any of its individual components, 47 | in Original or Modified Versions, may be sold by itself. 48 | 49 | 2) Original or Modified Versions of the Font Software may be bundled, 50 | redistributed and/or sold with any software, provided that each copy 51 | contains the above copyright notice and this license. These can be 52 | included either as stand-alone text files, human-readable headers or 53 | in the appropriate machine-readable metadata fields within text or 54 | binary files as long as those fields can be easily viewed by the user. 55 | 56 | 3) No Modified Version of the Font Software may use the Reserved Font 57 | Name(s) unless explicit written permission is granted by the corresponding 58 | Copyright Holder. This restriction only applies to the primary font name as 59 | presented to the users. 60 | 61 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 62 | Software shall not be used to promote, endorse or advertise any 63 | Modified Version, except to acknowledge the contribution(s) of the 64 | Copyright Holder(s) and the Author(s) or with their explicit written 65 | permission. 66 | 67 | 5) The Font Software, modified or unmodified, in part or in whole, 68 | must be distributed entirely under this license, and must not be 69 | distributed under any other license. The requirement for fonts to 70 | remain under this license does not apply to any document created 71 | using the Font Software. 72 | 73 | TERMINATION 74 | This license becomes null and void if any of the above conditions are 75 | not met. 76 | 77 | DISCLAIMER 78 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 79 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 80 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 81 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 82 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 83 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 84 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 85 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 86 | OTHER DEALINGS IN THE FONT SOFTWARE. 87 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/wwwroot/css/open-iconic/ICON-LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Waybury 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 13 | all 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 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/wwwroot/css/open-iconic/README.md: -------------------------------------------------------------------------------- 1 | [Open Iconic v1.1.1](https://github.com/iconic/open-iconic) 2 | =========== 3 | 4 | ### Open Iconic is the open source sibling of [Iconic](https://github.com/iconic/open-iconic). It is a hyper-legible collection of 223 icons with a tiny footprint—ready to use with Bootstrap and Foundation. [View the collection](https://github.com/iconic/open-iconic) 5 | 6 | 7 | 8 | ## What's in Open Iconic? 9 | 10 | * 223 icons designed to be legible down to 8 pixels 11 | * Super-light SVG files - 61.8 for the entire set 12 | * SVG sprite—the modern replacement for icon fonts 13 | * Webfont (EOT, OTF, SVG, TTF, WOFF), PNG and WebP formats 14 | * Webfont stylesheets (including versions for Bootstrap and Foundation) in CSS, LESS, SCSS and Stylus formats 15 | * PNG and WebP raster images in 8px, 16px, 24px, 32px, 48px and 64px. 16 | 17 | 18 | ## Getting Started 19 | 20 | #### For code samples and everything else you need to get started with Open Iconic, check out our [Icons](https://github.com/iconic/open-iconic) and [Reference](https://github.com/iconic/open-iconic) sections. 21 | 22 | ### General Usage 23 | 24 | #### Using Open Iconic's SVGs 25 | 26 | We like SVGs and we think they're the way to display icons on the web. Since Open Iconic are just basic SVGs, we suggest you display them like you would any other image (don't forget the `alt` attribute). 27 | 28 | ``` 29 | icon name 30 | ``` 31 | 32 | #### Using Open Iconic's SVG Sprite 33 | 34 | Open Iconic also comes in a SVG sprite which allows you to display all the icons in the set with a single request. It's like an icon font, without being a hack. 35 | 36 | Adding an icon from an SVG sprite is a little different than what you're used to, but it's still a piece of cake. *Tip: To make your icons easily style able, we suggest adding a general class to the* `` *tag and a unique class name for each different icon in the* `` *tag.* 37 | 38 | ``` 39 | 40 | 41 | 42 | ``` 43 | 44 | Sizing icons only needs basic CSS. All the icons are in a square format, so just set the `` tag with equal width and height dimensions. 45 | 46 | ``` 47 | .icon { 48 | width: 16px; 49 | height: 16px; 50 | } 51 | ``` 52 | 53 | Coloring icons is even easier. All you need to do is set the `fill` rule on the `` tag. 54 | 55 | ``` 56 | .icon-account-login { 57 | fill: #f00; 58 | } 59 | ``` 60 | 61 | To learn more about SVG Sprites, read [Chris Coyier's guide](http://css-tricks.com/svg-sprites-use-better-icon-fonts/). 62 | 63 | #### Using Open Iconic's Icon Font... 64 | 65 | 66 | ##### …with Bootstrap 67 | 68 | You can find our Bootstrap stylesheets in `font/css/open-iconic-bootstrap.{css, less, scss, styl}` 69 | 70 | 71 | ``` 72 | 73 | ``` 74 | 75 | 76 | ``` 77 | 78 | ``` 79 | 80 | ##### …with Foundation 81 | 82 | You can find our Foundation stylesheets in `font/css/open-iconic-foundation.{css, less, scss, styl}` 83 | 84 | ``` 85 | 86 | ``` 87 | 88 | 89 | ``` 90 | 91 | ``` 92 | 93 | ##### …on its own 94 | 95 | You can find our default stylesheets in `font/css/open-iconic.{css, less, scss, styl}` 96 | 97 | ``` 98 | 99 | ``` 100 | 101 | ``` 102 | 103 | ``` 104 | 105 | 106 | ## License 107 | 108 | ### Icons 109 | 110 | All code (including SVG markup) is under the [MIT License](http://opensource.org/licenses/MIT). 111 | 112 | ### Fonts 113 | 114 | All fonts are under the [SIL Licensed](http://scripts.sil.org/cms/scripts/page.php?item_id=OFL_web). 115 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/wwwroot/css/open-iconic/font/css/open-iconic-bootstrap.min.css: -------------------------------------------------------------------------------- 1 | @font-face{font-family:Icons;src:url(../fonts/open-iconic.eot);src:url(../fonts/open-iconic.eot?#iconic-sm) format('embedded-opentype'),url(../fonts/open-iconic.woff) format('woff'),url(../fonts/open-iconic.ttf) format('truetype'),url(../fonts/open-iconic.otf) format('opentype'),url(../fonts/open-iconic.svg#iconic-sm) format('svg');font-weight:400;font-style:normal}.oi{position:relative;top:1px;display:inline-block;speak:none;font-family:Icons;font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.oi:empty:before{width:1em;text-align:center;box-sizing:content-box}.oi.oi-align-center:before{text-align:center}.oi.oi-align-left:before{text-align:left}.oi.oi-align-right:before{text-align:right}.oi.oi-flip-horizontal:before{-webkit-transform:scale(-1,1);-ms-transform:scale(-1,1);transform:scale(-1,1)}.oi.oi-flip-vertical:before{-webkit-transform:scale(1,-1);-ms-transform:scale(-1,1);transform:scale(1,-1)}.oi.oi-flip-horizontal-vertical:before{-webkit-transform:scale(-1,-1);-ms-transform:scale(-1,1);transform:scale(-1,-1)}.oi-account-login:before{content:'\e000'}.oi-account-logout:before{content:'\e001'}.oi-action-redo:before{content:'\e002'}.oi-action-undo:before{content:'\e003'}.oi-align-center:before{content:'\e004'}.oi-align-left:before{content:'\e005'}.oi-align-right:before{content:'\e006'}.oi-aperture:before{content:'\e007'}.oi-arrow-bottom:before{content:'\e008'}.oi-arrow-circle-bottom:before{content:'\e009'}.oi-arrow-circle-left:before{content:'\e00a'}.oi-arrow-circle-right:before{content:'\e00b'}.oi-arrow-circle-top:before{content:'\e00c'}.oi-arrow-left:before{content:'\e00d'}.oi-arrow-right:before{content:'\e00e'}.oi-arrow-thick-bottom:before{content:'\e00f'}.oi-arrow-thick-left:before{content:'\e010'}.oi-arrow-thick-right:before{content:'\e011'}.oi-arrow-thick-top:before{content:'\e012'}.oi-arrow-top:before{content:'\e013'}.oi-audio-spectrum:before{content:'\e014'}.oi-audio:before{content:'\e015'}.oi-badge:before{content:'\e016'}.oi-ban:before{content:'\e017'}.oi-bar-chart:before{content:'\e018'}.oi-basket:before{content:'\e019'}.oi-battery-empty:before{content:'\e01a'}.oi-battery-full:before{content:'\e01b'}.oi-beaker:before{content:'\e01c'}.oi-bell:before{content:'\e01d'}.oi-bluetooth:before{content:'\e01e'}.oi-bold:before{content:'\e01f'}.oi-bolt:before{content:'\e020'}.oi-book:before{content:'\e021'}.oi-bookmark:before{content:'\e022'}.oi-box:before{content:'\e023'}.oi-briefcase:before{content:'\e024'}.oi-british-pound:before{content:'\e025'}.oi-browser:before{content:'\e026'}.oi-brush:before{content:'\e027'}.oi-bug:before{content:'\e028'}.oi-bullhorn:before{content:'\e029'}.oi-calculator:before{content:'\e02a'}.oi-calendar:before{content:'\e02b'}.oi-camera-slr:before{content:'\e02c'}.oi-caret-bottom:before{content:'\e02d'}.oi-caret-left:before{content:'\e02e'}.oi-caret-right:before{content:'\e02f'}.oi-caret-top:before{content:'\e030'}.oi-cart:before{content:'\e031'}.oi-chat:before{content:'\e032'}.oi-check:before{content:'\e033'}.oi-chevron-bottom:before{content:'\e034'}.oi-chevron-left:before{content:'\e035'}.oi-chevron-right:before{content:'\e036'}.oi-chevron-top:before{content:'\e037'}.oi-circle-check:before{content:'\e038'}.oi-circle-x:before{content:'\e039'}.oi-clipboard:before{content:'\e03a'}.oi-clock:before{content:'\e03b'}.oi-cloud-download:before{content:'\e03c'}.oi-cloud-upload:before{content:'\e03d'}.oi-cloud:before{content:'\e03e'}.oi-cloudy:before{content:'\e03f'}.oi-code:before{content:'\e040'}.oi-cog:before{content:'\e041'}.oi-collapse-down:before{content:'\e042'}.oi-collapse-left:before{content:'\e043'}.oi-collapse-right:before{content:'\e044'}.oi-collapse-up:before{content:'\e045'}.oi-command:before{content:'\e046'}.oi-comment-square:before{content:'\e047'}.oi-compass:before{content:'\e048'}.oi-contrast:before{content:'\e049'}.oi-copywriting:before{content:'\e04a'}.oi-credit-card:before{content:'\e04b'}.oi-crop:before{content:'\e04c'}.oi-dashboard:before{content:'\e04d'}.oi-data-transfer-download:before{content:'\e04e'}.oi-data-transfer-upload:before{content:'\e04f'}.oi-delete:before{content:'\e050'}.oi-dial:before{content:'\e051'}.oi-document:before{content:'\e052'}.oi-dollar:before{content:'\e053'}.oi-double-quote-sans-left:before{content:'\e054'}.oi-double-quote-sans-right:before{content:'\e055'}.oi-double-quote-serif-left:before{content:'\e056'}.oi-double-quote-serif-right:before{content:'\e057'}.oi-droplet:before{content:'\e058'}.oi-eject:before{content:'\e059'}.oi-elevator:before{content:'\e05a'}.oi-ellipses:before{content:'\e05b'}.oi-envelope-closed:before{content:'\e05c'}.oi-envelope-open:before{content:'\e05d'}.oi-euro:before{content:'\e05e'}.oi-excerpt:before{content:'\e05f'}.oi-expand-down:before{content:'\e060'}.oi-expand-left:before{content:'\e061'}.oi-expand-right:before{content:'\e062'}.oi-expand-up:before{content:'\e063'}.oi-external-link:before{content:'\e064'}.oi-eye:before{content:'\e065'}.oi-eyedropper:before{content:'\e066'}.oi-file:before{content:'\e067'}.oi-fire:before{content:'\e068'}.oi-flag:before{content:'\e069'}.oi-flash:before{content:'\e06a'}.oi-folder:before{content:'\e06b'}.oi-fork:before{content:'\e06c'}.oi-fullscreen-enter:before{content:'\e06d'}.oi-fullscreen-exit:before{content:'\e06e'}.oi-globe:before{content:'\e06f'}.oi-graph:before{content:'\e070'}.oi-grid-four-up:before{content:'\e071'}.oi-grid-three-up:before{content:'\e072'}.oi-grid-two-up:before{content:'\e073'}.oi-hard-drive:before{content:'\e074'}.oi-header:before{content:'\e075'}.oi-headphones:before{content:'\e076'}.oi-heart:before{content:'\e077'}.oi-home:before{content:'\e078'}.oi-image:before{content:'\e079'}.oi-inbox:before{content:'\e07a'}.oi-infinity:before{content:'\e07b'}.oi-info:before{content:'\e07c'}.oi-italic:before{content:'\e07d'}.oi-justify-center:before{content:'\e07e'}.oi-justify-left:before{content:'\e07f'}.oi-justify-right:before{content:'\e080'}.oi-key:before{content:'\e081'}.oi-laptop:before{content:'\e082'}.oi-layers:before{content:'\e083'}.oi-lightbulb:before{content:'\e084'}.oi-link-broken:before{content:'\e085'}.oi-link-intact:before{content:'\e086'}.oi-list-rich:before{content:'\e087'}.oi-list:before{content:'\e088'}.oi-location:before{content:'\e089'}.oi-lock-locked:before{content:'\e08a'}.oi-lock-unlocked:before{content:'\e08b'}.oi-loop-circular:before{content:'\e08c'}.oi-loop-square:before{content:'\e08d'}.oi-loop:before{content:'\e08e'}.oi-magnifying-glass:before{content:'\e08f'}.oi-map-marker:before{content:'\e090'}.oi-map:before{content:'\e091'}.oi-media-pause:before{content:'\e092'}.oi-media-play:before{content:'\e093'}.oi-media-record:before{content:'\e094'}.oi-media-skip-backward:before{content:'\e095'}.oi-media-skip-forward:before{content:'\e096'}.oi-media-step-backward:before{content:'\e097'}.oi-media-step-forward:before{content:'\e098'}.oi-media-stop:before{content:'\e099'}.oi-medical-cross:before{content:'\e09a'}.oi-menu:before{content:'\e09b'}.oi-microphone:before{content:'\e09c'}.oi-minus:before{content:'\e09d'}.oi-monitor:before{content:'\e09e'}.oi-moon:before{content:'\e09f'}.oi-move:before{content:'\e0a0'}.oi-musical-note:before{content:'\e0a1'}.oi-paperclip:before{content:'\e0a2'}.oi-pencil:before{content:'\e0a3'}.oi-people:before{content:'\e0a4'}.oi-person:before{content:'\e0a5'}.oi-phone:before{content:'\e0a6'}.oi-pie-chart:before{content:'\e0a7'}.oi-pin:before{content:'\e0a8'}.oi-play-circle:before{content:'\e0a9'}.oi-plus:before{content:'\e0aa'}.oi-power-standby:before{content:'\e0ab'}.oi-print:before{content:'\e0ac'}.oi-project:before{content:'\e0ad'}.oi-pulse:before{content:'\e0ae'}.oi-puzzle-piece:before{content:'\e0af'}.oi-question-mark:before{content:'\e0b0'}.oi-rain:before{content:'\e0b1'}.oi-random:before{content:'\e0b2'}.oi-reload:before{content:'\e0b3'}.oi-resize-both:before{content:'\e0b4'}.oi-resize-height:before{content:'\e0b5'}.oi-resize-width:before{content:'\e0b6'}.oi-rss-alt:before{content:'\e0b7'}.oi-rss:before{content:'\e0b8'}.oi-script:before{content:'\e0b9'}.oi-share-boxed:before{content:'\e0ba'}.oi-share:before{content:'\e0bb'}.oi-shield:before{content:'\e0bc'}.oi-signal:before{content:'\e0bd'}.oi-signpost:before{content:'\e0be'}.oi-sort-ascending:before{content:'\e0bf'}.oi-sort-descending:before{content:'\e0c0'}.oi-spreadsheet:before{content:'\e0c1'}.oi-star:before{content:'\e0c2'}.oi-sun:before{content:'\e0c3'}.oi-tablet:before{content:'\e0c4'}.oi-tag:before{content:'\e0c5'}.oi-tags:before{content:'\e0c6'}.oi-target:before{content:'\e0c7'}.oi-task:before{content:'\e0c8'}.oi-terminal:before{content:'\e0c9'}.oi-text:before{content:'\e0ca'}.oi-thumb-down:before{content:'\e0cb'}.oi-thumb-up:before{content:'\e0cc'}.oi-timer:before{content:'\e0cd'}.oi-transfer:before{content:'\e0ce'}.oi-trash:before{content:'\e0cf'}.oi-underline:before{content:'\e0d0'}.oi-vertical-align-bottom:before{content:'\e0d1'}.oi-vertical-align-center:before{content:'\e0d2'}.oi-vertical-align-top:before{content:'\e0d3'}.oi-video:before{content:'\e0d4'}.oi-volume-high:before{content:'\e0d5'}.oi-volume-low:before{content:'\e0d6'}.oi-volume-off:before{content:'\e0d7'}.oi-warning:before{content:'\e0d8'}.oi-wifi:before{content:'\e0d9'}.oi-wrench:before{content:'\e0da'}.oi-x:before{content:'\e0db'}.oi-yen:before{content:'\e0dc'}.oi-zoom-in:before{content:'\e0dd'}.oi-zoom-out:before{content:'\e0de'} -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/wwwroot/css/open-iconic/font/fonts/open-iconic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stavroskasidis/BlazorWithIdentity/f26d28fce6c6a52126634ba8131054c3ee77ffd0/template/BlazorWithIdentity.Client/wwwroot/css/open-iconic/font/fonts/open-iconic.eot -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/wwwroot/css/open-iconic/font/fonts/open-iconic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stavroskasidis/BlazorWithIdentity/f26d28fce6c6a52126634ba8131054c3ee77ffd0/template/BlazorWithIdentity.Client/wwwroot/css/open-iconic/font/fonts/open-iconic.otf -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/wwwroot/css/open-iconic/font/fonts/open-iconic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | Created by FontForge 20120731 at Tue Jul 1 20:39:22 2014 9 | By P.J. Onori 10 | Created by P.J. Onori with FontForge 2.0 (http://fontforge.sf.net) 11 | 12 | 13 | 14 | 27 | 28 | 30 | 32 | 34 | 36 | 38 | 40 | 42 | 45 | 47 | 49 | 51 | 53 | 55 | 57 | 59 | 61 | 63 | 65 | 67 | 69 | 71 | 74 | 76 | 79 | 81 | 84 | 86 | 88 | 91 | 93 | 95 | 98 | 100 | 102 | 104 | 106 | 109 | 112 | 115 | 117 | 121 | 123 | 125 | 127 | 130 | 132 | 134 | 136 | 138 | 141 | 143 | 145 | 147 | 149 | 151 | 153 | 155 | 157 | 159 | 162 | 165 | 167 | 169 | 172 | 174 | 177 | 179 | 181 | 183 | 185 | 189 | 191 | 194 | 196 | 198 | 200 | 202 | 205 | 207 | 209 | 211 | 213 | 215 | 218 | 220 | 222 | 224 | 226 | 228 | 230 | 232 | 234 | 236 | 238 | 241 | 243 | 245 | 247 | 249 | 251 | 253 | 256 | 259 | 261 | 263 | 265 | 267 | 269 | 272 | 274 | 276 | 280 | 282 | 285 | 287 | 289 | 292 | 295 | 298 | 300 | 302 | 304 | 306 | 309 | 312 | 314 | 316 | 318 | 320 | 322 | 324 | 326 | 330 | 334 | 338 | 340 | 343 | 345 | 347 | 349 | 351 | 353 | 355 | 358 | 360 | 363 | 365 | 367 | 369 | 371 | 373 | 375 | 377 | 379 | 381 | 383 | 386 | 388 | 390 | 392 | 394 | 396 | 399 | 401 | 404 | 406 | 408 | 410 | 412 | 414 | 416 | 419 | 421 | 423 | 425 | 428 | 431 | 435 | 438 | 440 | 442 | 444 | 446 | 448 | 451 | 453 | 455 | 457 | 460 | 462 | 464 | 466 | 468 | 471 | 473 | 477 | 479 | 481 | 483 | 486 | 488 | 490 | 492 | 494 | 496 | 499 | 501 | 504 | 506 | 509 | 512 | 515 | 517 | 520 | 522 | 524 | 526 | 529 | 532 | 534 | 536 | 539 | 542 | 543 | 544 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stavroskasidis/BlazorWithIdentity/f26d28fce6c6a52126634ba8131054c3ee77ffd0/template/BlazorWithIdentity.Client/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/wwwroot/css/open-iconic/font/fonts/open-iconic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stavroskasidis/BlazorWithIdentity/f26d28fce6c6a52126634ba8131054c3ee77ffd0/template/BlazorWithIdentity.Client/wwwroot/css/open-iconic/font/fonts/open-iconic.woff -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/wwwroot/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stavroskasidis/BlazorWithIdentity/f26d28fce6c6a52126634ba8131054c3ee77ffd0/template/BlazorWithIdentity.Client/wwwroot/favicon.png -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/wwwroot/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stavroskasidis/BlazorWithIdentity/f26d28fce6c6a52126634ba8131054c3ee77ffd0/template/BlazorWithIdentity.Client/wwwroot/icon-192.png -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Client/wwwroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | BlazorWithIdentity 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 |
22 |
23 | 24 |
25 | An unhandled error has occurred. 26 | Reload 27 | 🗙 28 |
29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Server/BlazorWithIdentity.Server.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Server/Controllers/AuthorizeController.cs: -------------------------------------------------------------------------------- 1 | using BlazorWithIdentity.Server.Models; 2 | using BlazorWithIdentity.Shared; 3 | using Microsoft.AspNetCore.Authorization; 4 | using Microsoft.AspNetCore.Identity; 5 | using Microsoft.AspNetCore.Mvc; 6 | 7 | namespace BlazorWithIdentity.Server.Controllers 8 | { 9 | [Route("api/[controller]/[action]")] 10 | [ApiController] 11 | public class AuthorizeController : ControllerBase 12 | { 13 | private readonly UserManager _userManager; 14 | private readonly SignInManager _signInManager; 15 | 16 | public AuthorizeController(UserManager userManager, SignInManager signInManager) 17 | { 18 | _userManager = userManager; 19 | _signInManager = signInManager; 20 | } 21 | 22 | [HttpPost] 23 | public async Task Login(LoginParameters parameters) 24 | { 25 | var user = await _userManager.FindByNameAsync(parameters.UserName); 26 | if (user == null) return BadRequest("User does not exist"); 27 | var singInResult = await _signInManager.CheckPasswordSignInAsync(user, parameters.Password, false); 28 | if (!singInResult.Succeeded) return BadRequest("Invalid password"); 29 | 30 | await _signInManager.SignInAsync(user, parameters.RememberMe); 31 | 32 | return Ok(); 33 | } 34 | 35 | 36 | [HttpPost] 37 | public async Task Register(RegisterParameters parameters) 38 | { 39 | var user = new ApplicationUser(); 40 | user.UserName = parameters.UserName; 41 | var result = await _userManager.CreateAsync(user, parameters.Password); 42 | if (!result.Succeeded) return BadRequest(result.Errors.FirstOrDefault()?.Description); 43 | 44 | return await Login(new LoginParameters 45 | { 46 | UserName = parameters.UserName, 47 | Password = parameters.Password 48 | }); 49 | } 50 | 51 | [Authorize] 52 | [HttpPost] 53 | public async Task Logout() 54 | { 55 | await _signInManager.SignOutAsync(); 56 | return Ok(); 57 | } 58 | 59 | [HttpGet] 60 | public UserInfo UserInfo() 61 | { 62 | //var user = await _userManager.GetUserAsync(HttpContext.User); 63 | return BuildUserInfo(); 64 | } 65 | 66 | 67 | private UserInfo BuildUserInfo() 68 | { 69 | return new UserInfo 70 | { 71 | IsAuthenticated = User.Identity.IsAuthenticated, 72 | UserName = User.Identity.Name, 73 | ExposedClaims = User.Claims 74 | //Optionally: filter the claims you want to expose to the client 75 | //.Where(c => c.Type == "test-claim") 76 | .ToDictionary(c => c.Type, c => c.Value) 77 | }; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Server/Controllers/SampleDataController.cs: -------------------------------------------------------------------------------- 1 | using BlazorWithIdentity.Shared; 2 | using Microsoft.AspNetCore.Authorization; 3 | using Microsoft.AspNetCore.Mvc; 4 | 5 | namespace BlazorWithIdentity.Server.Controllers 6 | { 7 | [Route("api/[controller]")] 8 | [Authorize] 9 | public class SampleDataController : Controller 10 | { 11 | private static string[] Summaries = new[] 12 | { 13 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" 14 | }; 15 | 16 | [HttpGet("[action]")] 17 | public IEnumerable WeatherForecasts() 18 | { 19 | var rng = new Random(); 20 | return Enumerable.Range(1, 5).Select(index => new WeatherForecast 21 | { 22 | Date = DateTime.Now.AddDays(index), 23 | TemperatureC = rng.Next(-20, 55), 24 | Summary = Summaries[rng.Next(Summaries.Length)] 25 | }); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Server/Data/ApplicationDbContext.cs: -------------------------------------------------------------------------------- 1 | using BlazorWithIdentity.Server.Models; 2 | using Microsoft.AspNetCore.Identity; 3 | using Microsoft.AspNetCore.Identity.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Threading.Tasks; 9 | 10 | namespace BlazorWithIdentity.Server.Data 11 | { 12 | public class ApplicationDbContext : IdentityDbContext, Guid> 13 | { 14 | public ApplicationDbContext(DbContextOptions options) 15 | : base(options) 16 | { 17 | } 18 | 19 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 20 | { 21 | base.OnConfiguring(optionsBuilder); 22 | } 23 | 24 | protected override void OnModelCreating(ModelBuilder builder) 25 | { 26 | base.OnModelCreating(builder); 27 | // Customize the ASP.NET Identity model and override the defaults if needed. 28 | // For example, you can rename the ASP.NET Identity table names and more. 29 | // Add your customizations after calling base.OnModelCreating(builder); 30 | 31 | } 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Server/Migrations/20190502083628_Init.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using BlazorWithIdentity.Server.Data; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Infrastructure; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | 9 | namespace BlazorWithIdentity.Server.Migrations 10 | { 11 | [DbContext(typeof(ApplicationDbContext))] 12 | [Migration("20190502083628_Init")] 13 | partial class Init 14 | { 15 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 16 | { 17 | #pragma warning disable 612, 618 18 | modelBuilder 19 | .HasAnnotation("ProductVersion", "3.0.0-preview3.19153.1"); 20 | 21 | modelBuilder.Entity("BlazorWithIdentity.Server.Models.ApplicationUser", b => 22 | { 23 | b.Property("Id") 24 | .ValueGeneratedOnAdd(); 25 | 26 | b.Property("AccessFailedCount"); 27 | 28 | b.Property("ConcurrencyStamp") 29 | .IsConcurrencyToken(); 30 | 31 | b.Property("Email") 32 | .HasMaxLength(256); 33 | 34 | b.Property("EmailConfirmed"); 35 | 36 | b.Property("LockoutEnabled"); 37 | 38 | b.Property("LockoutEnd"); 39 | 40 | b.Property("NormalizedEmail") 41 | .HasMaxLength(256); 42 | 43 | b.Property("NormalizedUserName") 44 | .HasMaxLength(256); 45 | 46 | b.Property("PasswordHash"); 47 | 48 | b.Property("PhoneNumber"); 49 | 50 | b.Property("PhoneNumberConfirmed"); 51 | 52 | b.Property("SecurityStamp"); 53 | 54 | b.Property("TwoFactorEnabled"); 55 | 56 | b.Property("UserName") 57 | .HasMaxLength(256); 58 | 59 | b.HasKey("Id"); 60 | 61 | b.HasIndex("NormalizedEmail") 62 | .HasName("EmailIndex"); 63 | 64 | b.HasIndex("NormalizedUserName") 65 | .IsUnique() 66 | .HasName("UserNameIndex"); 67 | 68 | b.ToTable("AspNetUsers"); 69 | }); 70 | 71 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => 72 | { 73 | b.Property("Id") 74 | .ValueGeneratedOnAdd(); 75 | 76 | b.Property("ConcurrencyStamp") 77 | .IsConcurrencyToken(); 78 | 79 | b.Property("Name") 80 | .HasMaxLength(256); 81 | 82 | b.Property("NormalizedName") 83 | .HasMaxLength(256); 84 | 85 | b.HasKey("Id"); 86 | 87 | b.HasIndex("NormalizedName") 88 | .IsUnique() 89 | .HasName("RoleNameIndex"); 90 | 91 | b.ToTable("AspNetRoles"); 92 | }); 93 | 94 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 95 | { 96 | b.Property("Id") 97 | .ValueGeneratedOnAdd(); 98 | 99 | b.Property("ClaimType"); 100 | 101 | b.Property("ClaimValue"); 102 | 103 | b.Property("RoleId"); 104 | 105 | b.HasKey("Id"); 106 | 107 | b.HasIndex("RoleId"); 108 | 109 | b.ToTable("AspNetRoleClaims"); 110 | }); 111 | 112 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 113 | { 114 | b.Property("Id") 115 | .ValueGeneratedOnAdd(); 116 | 117 | b.Property("ClaimType"); 118 | 119 | b.Property("ClaimValue"); 120 | 121 | b.Property("UserId"); 122 | 123 | b.HasKey("Id"); 124 | 125 | b.HasIndex("UserId"); 126 | 127 | b.ToTable("AspNetUserClaims"); 128 | }); 129 | 130 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 131 | { 132 | b.Property("LoginProvider"); 133 | 134 | b.Property("ProviderKey"); 135 | 136 | b.Property("ProviderDisplayName"); 137 | 138 | b.Property("UserId"); 139 | 140 | b.HasKey("LoginProvider", "ProviderKey"); 141 | 142 | b.HasIndex("UserId"); 143 | 144 | b.ToTable("AspNetUserLogins"); 145 | }); 146 | 147 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 148 | { 149 | b.Property("UserId"); 150 | 151 | b.Property("RoleId"); 152 | 153 | b.HasKey("UserId", "RoleId"); 154 | 155 | b.HasIndex("RoleId"); 156 | 157 | b.ToTable("AspNetUserRoles"); 158 | }); 159 | 160 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 161 | { 162 | b.Property("UserId"); 163 | 164 | b.Property("LoginProvider"); 165 | 166 | b.Property("Name"); 167 | 168 | b.Property("Value"); 169 | 170 | b.HasKey("UserId", "LoginProvider", "Name"); 171 | 172 | b.ToTable("AspNetUserTokens"); 173 | }); 174 | 175 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 176 | { 177 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") 178 | .WithMany() 179 | .HasForeignKey("RoleId") 180 | .OnDelete(DeleteBehavior.Cascade); 181 | }); 182 | 183 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 184 | { 185 | b.HasOne("BlazorWithIdentity.Server.Models.ApplicationUser") 186 | .WithMany() 187 | .HasForeignKey("UserId") 188 | .OnDelete(DeleteBehavior.Cascade); 189 | }); 190 | 191 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 192 | { 193 | b.HasOne("BlazorWithIdentity.Server.Models.ApplicationUser") 194 | .WithMany() 195 | .HasForeignKey("UserId") 196 | .OnDelete(DeleteBehavior.Cascade); 197 | }); 198 | 199 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 200 | { 201 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") 202 | .WithMany() 203 | .HasForeignKey("RoleId") 204 | .OnDelete(DeleteBehavior.Cascade); 205 | 206 | b.HasOne("BlazorWithIdentity.Server.Models.ApplicationUser") 207 | .WithMany() 208 | .HasForeignKey("UserId") 209 | .OnDelete(DeleteBehavior.Cascade); 210 | }); 211 | 212 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 213 | { 214 | b.HasOne("BlazorWithIdentity.Server.Models.ApplicationUser") 215 | .WithMany() 216 | .HasForeignKey("UserId") 217 | .OnDelete(DeleteBehavior.Cascade); 218 | }); 219 | #pragma warning restore 612, 618 220 | } 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Server/Migrations/20190502083628_Init.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Migrations; 3 | 4 | namespace BlazorWithIdentity.Server.Migrations 5 | { 6 | public partial class Init : Migration 7 | { 8 | protected override void Up(MigrationBuilder migrationBuilder) 9 | { 10 | migrationBuilder.CreateTable( 11 | name: "AspNetRoles", 12 | columns: table => new 13 | { 14 | Id = table.Column(nullable: false), 15 | Name = table.Column(maxLength: 256, nullable: true), 16 | NormalizedName = table.Column(maxLength: 256, nullable: true), 17 | ConcurrencyStamp = table.Column(nullable: true) 18 | }, 19 | constraints: table => 20 | { 21 | table.PrimaryKey("PK_AspNetRoles", x => x.Id); 22 | }); 23 | 24 | migrationBuilder.CreateTable( 25 | name: "AspNetUsers", 26 | columns: table => new 27 | { 28 | Id = table.Column(nullable: false), 29 | UserName = table.Column(maxLength: 256, nullable: true), 30 | NormalizedUserName = table.Column(maxLength: 256, nullable: true), 31 | Email = table.Column(maxLength: 256, nullable: true), 32 | NormalizedEmail = table.Column(maxLength: 256, nullable: true), 33 | EmailConfirmed = table.Column(nullable: false), 34 | PasswordHash = table.Column(nullable: true), 35 | SecurityStamp = table.Column(nullable: true), 36 | ConcurrencyStamp = table.Column(nullable: true), 37 | PhoneNumber = table.Column(nullable: true), 38 | PhoneNumberConfirmed = table.Column(nullable: false), 39 | TwoFactorEnabled = table.Column(nullable: false), 40 | LockoutEnd = table.Column(nullable: true), 41 | LockoutEnabled = table.Column(nullable: false), 42 | AccessFailedCount = table.Column(nullable: false) 43 | }, 44 | constraints: table => 45 | { 46 | table.PrimaryKey("PK_AspNetUsers", x => x.Id); 47 | }); 48 | 49 | migrationBuilder.CreateTable( 50 | name: "AspNetRoleClaims", 51 | columns: table => new 52 | { 53 | Id = table.Column(nullable: false) 54 | .Annotation("Sqlite:Autoincrement", true), 55 | RoleId = table.Column(nullable: false), 56 | ClaimType = table.Column(nullable: true), 57 | ClaimValue = table.Column(nullable: true) 58 | }, 59 | constraints: table => 60 | { 61 | table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id); 62 | table.ForeignKey( 63 | name: "FK_AspNetRoleClaims_AspNetRoles_RoleId", 64 | column: x => x.RoleId, 65 | principalTable: "AspNetRoles", 66 | principalColumn: "Id", 67 | onDelete: ReferentialAction.Cascade); 68 | }); 69 | 70 | migrationBuilder.CreateTable( 71 | name: "AspNetUserClaims", 72 | columns: table => new 73 | { 74 | Id = table.Column(nullable: false) 75 | .Annotation("Sqlite:Autoincrement", true), 76 | UserId = table.Column(nullable: false), 77 | ClaimType = table.Column(nullable: true), 78 | ClaimValue = table.Column(nullable: true) 79 | }, 80 | constraints: table => 81 | { 82 | table.PrimaryKey("PK_AspNetUserClaims", x => x.Id); 83 | table.ForeignKey( 84 | name: "FK_AspNetUserClaims_AspNetUsers_UserId", 85 | column: x => x.UserId, 86 | principalTable: "AspNetUsers", 87 | principalColumn: "Id", 88 | onDelete: ReferentialAction.Cascade); 89 | }); 90 | 91 | migrationBuilder.CreateTable( 92 | name: "AspNetUserLogins", 93 | columns: table => new 94 | { 95 | LoginProvider = table.Column(nullable: false), 96 | ProviderKey = table.Column(nullable: false), 97 | ProviderDisplayName = table.Column(nullable: true), 98 | UserId = table.Column(nullable: false) 99 | }, 100 | constraints: table => 101 | { 102 | table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey }); 103 | table.ForeignKey( 104 | name: "FK_AspNetUserLogins_AspNetUsers_UserId", 105 | column: x => x.UserId, 106 | principalTable: "AspNetUsers", 107 | principalColumn: "Id", 108 | onDelete: ReferentialAction.Cascade); 109 | }); 110 | 111 | migrationBuilder.CreateTable( 112 | name: "AspNetUserRoles", 113 | columns: table => new 114 | { 115 | UserId = table.Column(nullable: false), 116 | RoleId = table.Column(nullable: false) 117 | }, 118 | constraints: table => 119 | { 120 | table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId }); 121 | table.ForeignKey( 122 | name: "FK_AspNetUserRoles_AspNetRoles_RoleId", 123 | column: x => x.RoleId, 124 | principalTable: "AspNetRoles", 125 | principalColumn: "Id", 126 | onDelete: ReferentialAction.Cascade); 127 | table.ForeignKey( 128 | name: "FK_AspNetUserRoles_AspNetUsers_UserId", 129 | column: x => x.UserId, 130 | principalTable: "AspNetUsers", 131 | principalColumn: "Id", 132 | onDelete: ReferentialAction.Cascade); 133 | }); 134 | 135 | migrationBuilder.CreateTable( 136 | name: "AspNetUserTokens", 137 | columns: table => new 138 | { 139 | UserId = table.Column(nullable: false), 140 | LoginProvider = table.Column(nullable: false), 141 | Name = table.Column(nullable: false), 142 | Value = table.Column(nullable: true) 143 | }, 144 | constraints: table => 145 | { 146 | table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); 147 | table.ForeignKey( 148 | name: "FK_AspNetUserTokens_AspNetUsers_UserId", 149 | column: x => x.UserId, 150 | principalTable: "AspNetUsers", 151 | principalColumn: "Id", 152 | onDelete: ReferentialAction.Cascade); 153 | }); 154 | 155 | migrationBuilder.CreateIndex( 156 | name: "IX_AspNetRoleClaims_RoleId", 157 | table: "AspNetRoleClaims", 158 | column: "RoleId"); 159 | 160 | migrationBuilder.CreateIndex( 161 | name: "RoleNameIndex", 162 | table: "AspNetRoles", 163 | column: "NormalizedName", 164 | unique: true); 165 | 166 | migrationBuilder.CreateIndex( 167 | name: "IX_AspNetUserClaims_UserId", 168 | table: "AspNetUserClaims", 169 | column: "UserId"); 170 | 171 | migrationBuilder.CreateIndex( 172 | name: "IX_AspNetUserLogins_UserId", 173 | table: "AspNetUserLogins", 174 | column: "UserId"); 175 | 176 | migrationBuilder.CreateIndex( 177 | name: "IX_AspNetUserRoles_RoleId", 178 | table: "AspNetUserRoles", 179 | column: "RoleId"); 180 | 181 | migrationBuilder.CreateIndex( 182 | name: "EmailIndex", 183 | table: "AspNetUsers", 184 | column: "NormalizedEmail"); 185 | 186 | migrationBuilder.CreateIndex( 187 | name: "UserNameIndex", 188 | table: "AspNetUsers", 189 | column: "NormalizedUserName", 190 | unique: true); 191 | } 192 | 193 | protected override void Down(MigrationBuilder migrationBuilder) 194 | { 195 | migrationBuilder.DropTable( 196 | name: "AspNetRoleClaims"); 197 | 198 | migrationBuilder.DropTable( 199 | name: "AspNetUserClaims"); 200 | 201 | migrationBuilder.DropTable( 202 | name: "AspNetUserLogins"); 203 | 204 | migrationBuilder.DropTable( 205 | name: "AspNetUserRoles"); 206 | 207 | migrationBuilder.DropTable( 208 | name: "AspNetUserTokens"); 209 | 210 | migrationBuilder.DropTable( 211 | name: "AspNetRoles"); 212 | 213 | migrationBuilder.DropTable( 214 | name: "AspNetUsers"); 215 | } 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Server/Migrations/ApplicationDbContextModelSnapshot.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using BlazorWithIdentity.Server.Data; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Infrastructure; 6 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 7 | 8 | namespace BlazorWithIdentity.Server.Migrations 9 | { 10 | [DbContext(typeof(ApplicationDbContext))] 11 | partial class ApplicationDbContextModelSnapshot : ModelSnapshot 12 | { 13 | protected override void BuildModel(ModelBuilder modelBuilder) 14 | { 15 | #pragma warning disable 612, 618 16 | modelBuilder 17 | .HasAnnotation("ProductVersion", "3.0.0-preview3.19153.1"); 18 | 19 | modelBuilder.Entity("BlazorWithIdentity.Server.Models.ApplicationUser", b => 20 | { 21 | b.Property("Id") 22 | .ValueGeneratedOnAdd(); 23 | 24 | b.Property("AccessFailedCount"); 25 | 26 | b.Property("ConcurrencyStamp") 27 | .IsConcurrencyToken(); 28 | 29 | b.Property("Email") 30 | .HasMaxLength(256); 31 | 32 | b.Property("EmailConfirmed"); 33 | 34 | b.Property("LockoutEnabled"); 35 | 36 | b.Property("LockoutEnd"); 37 | 38 | b.Property("NormalizedEmail") 39 | .HasMaxLength(256); 40 | 41 | b.Property("NormalizedUserName") 42 | .HasMaxLength(256); 43 | 44 | b.Property("PasswordHash"); 45 | 46 | b.Property("PhoneNumber"); 47 | 48 | b.Property("PhoneNumberConfirmed"); 49 | 50 | b.Property("SecurityStamp"); 51 | 52 | b.Property("TwoFactorEnabled"); 53 | 54 | b.Property("UserName") 55 | .HasMaxLength(256); 56 | 57 | b.HasKey("Id"); 58 | 59 | b.HasIndex("NormalizedEmail") 60 | .HasName("EmailIndex"); 61 | 62 | b.HasIndex("NormalizedUserName") 63 | .IsUnique() 64 | .HasName("UserNameIndex"); 65 | 66 | b.ToTable("AspNetUsers"); 67 | }); 68 | 69 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => 70 | { 71 | b.Property("Id") 72 | .ValueGeneratedOnAdd(); 73 | 74 | b.Property("ConcurrencyStamp") 75 | .IsConcurrencyToken(); 76 | 77 | b.Property("Name") 78 | .HasMaxLength(256); 79 | 80 | b.Property("NormalizedName") 81 | .HasMaxLength(256); 82 | 83 | b.HasKey("Id"); 84 | 85 | b.HasIndex("NormalizedName") 86 | .IsUnique() 87 | .HasName("RoleNameIndex"); 88 | 89 | b.ToTable("AspNetRoles"); 90 | }); 91 | 92 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 93 | { 94 | b.Property("Id") 95 | .ValueGeneratedOnAdd(); 96 | 97 | b.Property("ClaimType"); 98 | 99 | b.Property("ClaimValue"); 100 | 101 | b.Property("RoleId"); 102 | 103 | b.HasKey("Id"); 104 | 105 | b.HasIndex("RoleId"); 106 | 107 | b.ToTable("AspNetRoleClaims"); 108 | }); 109 | 110 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 111 | { 112 | b.Property("Id") 113 | .ValueGeneratedOnAdd(); 114 | 115 | b.Property("ClaimType"); 116 | 117 | b.Property("ClaimValue"); 118 | 119 | b.Property("UserId"); 120 | 121 | b.HasKey("Id"); 122 | 123 | b.HasIndex("UserId"); 124 | 125 | b.ToTable("AspNetUserClaims"); 126 | }); 127 | 128 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 129 | { 130 | b.Property("LoginProvider"); 131 | 132 | b.Property("ProviderKey"); 133 | 134 | b.Property("ProviderDisplayName"); 135 | 136 | b.Property("UserId"); 137 | 138 | b.HasKey("LoginProvider", "ProviderKey"); 139 | 140 | b.HasIndex("UserId"); 141 | 142 | b.ToTable("AspNetUserLogins"); 143 | }); 144 | 145 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 146 | { 147 | b.Property("UserId"); 148 | 149 | b.Property("RoleId"); 150 | 151 | b.HasKey("UserId", "RoleId"); 152 | 153 | b.HasIndex("RoleId"); 154 | 155 | b.ToTable("AspNetUserRoles"); 156 | }); 157 | 158 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 159 | { 160 | b.Property("UserId"); 161 | 162 | b.Property("LoginProvider"); 163 | 164 | b.Property("Name"); 165 | 166 | b.Property("Value"); 167 | 168 | b.HasKey("UserId", "LoginProvider", "Name"); 169 | 170 | b.ToTable("AspNetUserTokens"); 171 | }); 172 | 173 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 174 | { 175 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") 176 | .WithMany() 177 | .HasForeignKey("RoleId") 178 | .OnDelete(DeleteBehavior.Cascade); 179 | }); 180 | 181 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 182 | { 183 | b.HasOne("BlazorWithIdentity.Server.Models.ApplicationUser") 184 | .WithMany() 185 | .HasForeignKey("UserId") 186 | .OnDelete(DeleteBehavior.Cascade); 187 | }); 188 | 189 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 190 | { 191 | b.HasOne("BlazorWithIdentity.Server.Models.ApplicationUser") 192 | .WithMany() 193 | .HasForeignKey("UserId") 194 | .OnDelete(DeleteBehavior.Cascade); 195 | }); 196 | 197 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 198 | { 199 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") 200 | .WithMany() 201 | .HasForeignKey("RoleId") 202 | .OnDelete(DeleteBehavior.Cascade); 203 | 204 | b.HasOne("BlazorWithIdentity.Server.Models.ApplicationUser") 205 | .WithMany() 206 | .HasForeignKey("UserId") 207 | .OnDelete(DeleteBehavior.Cascade); 208 | }); 209 | 210 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 211 | { 212 | b.HasOne("BlazorWithIdentity.Server.Models.ApplicationUser") 213 | .WithMany() 214 | .HasForeignKey("UserId") 215 | .OnDelete(DeleteBehavior.Cascade); 216 | }); 217 | #pragma warning restore 612, 618 218 | } 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Server/Models/ApplicationUser.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Identity; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace BlazorWithIdentity.Server.Models 8 | { 9 | public class ApplicationUser : IdentityUser 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Server/Program.cs: -------------------------------------------------------------------------------- 1 | using BlazorWithIdentity.Server.Data; 2 | using BlazorWithIdentity.Server.Models; 3 | using Microsoft.AspNetCore.Identity; 4 | using Microsoft.EntityFrameworkCore; 5 | 6 | var builder = WebApplication.CreateBuilder(args); 7 | 8 | // Add services to the container. 9 | builder.Services.AddDbContext(options => 10 | options.UseSqlite("Filename=data.db")); 11 | 12 | builder.Services.AddIdentity>() 13 | .AddEntityFrameworkStores() 14 | .AddDefaultTokenProviders(); 15 | 16 | builder.Services.Configure(options => 17 | { 18 | // Password settings 19 | options.Password.RequireDigit = true; 20 | options.Password.RequiredLength = 6; 21 | options.Password.RequireNonAlphanumeric = true; 22 | options.Password.RequireUppercase = true; 23 | options.Password.RequireLowercase = false; 24 | 25 | // Lockout settings 26 | options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30); 27 | options.Lockout.MaxFailedAccessAttempts = 10; 28 | options.Lockout.AllowedForNewUsers = true; 29 | 30 | // User settings 31 | options.User.RequireUniqueEmail = false; 32 | }); 33 | 34 | builder.Services.ConfigureApplicationCookie(options => 35 | { 36 | options.Cookie.HttpOnly = true; 37 | options.Events.OnRedirectToLogin = context => 38 | { 39 | context.Response.StatusCode = 401; 40 | return Task.CompletedTask; 41 | }; 42 | }); 43 | 44 | 45 | builder.Services.AddControllersWithViews(); 46 | builder.Services.AddRazorPages(); 47 | 48 | var app = builder.Build(); 49 | 50 | // Configure the HTTP request pipeline. 51 | if (app.Environment.IsDevelopment()) 52 | { 53 | using (var serviceScope = app.Services.GetRequiredService().CreateScope()) 54 | { 55 | //Note: Microsoft recommends to NOT migrate your database at Startup. 56 | //You should consider your migration strategy according to the guidelines. 57 | serviceScope.ServiceProvider.GetRequiredService().Database.Migrate(); 58 | } 59 | 60 | app.UseWebAssemblyDebugging(); 61 | } 62 | else 63 | { 64 | app.UseExceptionHandler("/Error"); 65 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. 66 | app.UseHsts(); 67 | } 68 | 69 | app.UseHttpsRedirection(); 70 | 71 | app.UseBlazorFrameworkFiles(); 72 | app.UseStaticFiles(); 73 | 74 | app.UseRouting(); 75 | app.UseAuthentication(); 76 | app.UseAuthorization(); 77 | 78 | app.MapRazorPages(); 79 | app.MapControllers(); 80 | app.MapFallbackToFile("index.html"); 81 | 82 | app.Run(); 83 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Server/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:53415", 7 | "sslPort": 44370 8 | } 9 | }, 10 | "profiles": { 11 | "BlazorWithIdentity.Server": { 12 | "commandName": "Project", 13 | "dotnetRunMessages": true, 14 | "launchBrowser": true, 15 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 16 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 17 | "environmentVariables": { 18 | "ASPNETCORE_ENVIRONMENT": "Development" 19 | } 20 | }, 21 | "IIS Express": { 22 | "commandName": "IISExpress", 23 | "launchBrowser": true, 24 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 25 | "environmentVariables": { 26 | "ASPNETCORE_ENVIRONMENT": "Development" 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Server/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Server/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Shared/BlazorWithIdentity.Shared.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Shared/LoginParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Text; 5 | 6 | namespace BlazorWithIdentity.Shared 7 | { 8 | public class LoginParameters 9 | { 10 | [Required] 11 | public string UserName { get; set; } 12 | 13 | [Required] 14 | public string Password { get; set; } 15 | 16 | public bool RememberMe { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Shared/RegisterParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Text; 5 | 6 | namespace BlazorWithIdentity.Shared 7 | { 8 | public class RegisterParameters 9 | { 10 | [Required] 11 | public string UserName { get; set; } 12 | 13 | [Required] 14 | public string Password { get; set; } 15 | 16 | [Required] 17 | [Compare(nameof(Password), ErrorMessage = "Passwords do not match")] 18 | public string PasswordConfirm { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Shared/UserInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace BlazorWithIdentity.Shared 6 | { 7 | public class UserInfo 8 | { 9 | public bool IsAuthenticated { get; set; } 10 | public string UserName { get; set; } 11 | public Dictionary ExposedClaims { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.Shared/WeatherForecast.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace BlazorWithIdentity.Shared 6 | { 7 | public class WeatherForecast 8 | { 9 | public DateTime Date { get; set; } 10 | 11 | public int TemperatureC { get; set; } 12 | 13 | public string Summary { get; set; } 14 | 15 | public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /template/BlazorWithIdentity.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26124.0 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlazorWithIdentity.Server", "BlazorWithIdentity.Server\BlazorWithIdentity.Server.csproj", "{A707002F-F9D5-4133-9AC7-483418D94C7E}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlazorWithIdentity.Client", "BlazorWithIdentity.Client\BlazorWithIdentity.Client.csproj", "{8BAEDA0D-7C16-40C7-BEF2-B77FA7F2AB0D}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlazorWithIdentity.Shared", "BlazorWithIdentity.Shared\BlazorWithIdentity.Shared.csproj", "{4506B124-94D1-4DA4-A81B-842A2F6B95E6}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Debug|x64 = Debug|x64 16 | Debug|x86 = Debug|x86 17 | Release|Any CPU = Release|Any CPU 18 | Release|x64 = Release|x64 19 | Release|x86 = Release|x86 20 | EndGlobalSection 21 | GlobalSection(SolutionProperties) = preSolution 22 | HideSolutionNode = FALSE 23 | EndGlobalSection 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 25 | {8BAEDA0D-7C16-40C7-BEF2-B77FA7F2AB0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {8BAEDA0D-7C16-40C7-BEF2-B77FA7F2AB0D}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {8BAEDA0D-7C16-40C7-BEF2-B77FA7F2AB0D}.Debug|x64.ActiveCfg = Debug|Any CPU 28 | {8BAEDA0D-7C16-40C7-BEF2-B77FA7F2AB0D}.Debug|x64.Build.0 = Debug|Any CPU 29 | {8BAEDA0D-7C16-40C7-BEF2-B77FA7F2AB0D}.Debug|x86.ActiveCfg = Debug|Any CPU 30 | {8BAEDA0D-7C16-40C7-BEF2-B77FA7F2AB0D}.Debug|x86.Build.0 = Debug|Any CPU 31 | {8BAEDA0D-7C16-40C7-BEF2-B77FA7F2AB0D}.Release|Any CPU.ActiveCfg = Release|Any CPU 32 | {8BAEDA0D-7C16-40C7-BEF2-B77FA7F2AB0D}.Release|Any CPU.Build.0 = Release|Any CPU 33 | {8BAEDA0D-7C16-40C7-BEF2-B77FA7F2AB0D}.Release|x64.ActiveCfg = Release|Any CPU 34 | {8BAEDA0D-7C16-40C7-BEF2-B77FA7F2AB0D}.Release|x64.Build.0 = Release|Any CPU 35 | {8BAEDA0D-7C16-40C7-BEF2-B77FA7F2AB0D}.Release|x86.ActiveCfg = Release|Any CPU 36 | {8BAEDA0D-7C16-40C7-BEF2-B77FA7F2AB0D}.Release|x86.Build.0 = Release|Any CPU 37 | {A707002F-F9D5-4133-9AC7-483418D94C7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 38 | {A707002F-F9D5-4133-9AC7-483418D94C7E}.Debug|Any CPU.Build.0 = Debug|Any CPU 39 | {A707002F-F9D5-4133-9AC7-483418D94C7E}.Debug|x64.ActiveCfg = Debug|Any CPU 40 | {A707002F-F9D5-4133-9AC7-483418D94C7E}.Debug|x64.Build.0 = Debug|Any CPU 41 | {A707002F-F9D5-4133-9AC7-483418D94C7E}.Debug|x86.ActiveCfg = Debug|Any CPU 42 | {A707002F-F9D5-4133-9AC7-483418D94C7E}.Debug|x86.Build.0 = Debug|Any CPU 43 | {A707002F-F9D5-4133-9AC7-483418D94C7E}.Release|Any CPU.ActiveCfg = Release|Any CPU 44 | {A707002F-F9D5-4133-9AC7-483418D94C7E}.Release|Any CPU.Build.0 = Release|Any CPU 45 | {A707002F-F9D5-4133-9AC7-483418D94C7E}.Release|x64.ActiveCfg = Release|Any CPU 46 | {A707002F-F9D5-4133-9AC7-483418D94C7E}.Release|x64.Build.0 = Release|Any CPU 47 | {A707002F-F9D5-4133-9AC7-483418D94C7E}.Release|x86.ActiveCfg = Release|Any CPU 48 | {A707002F-F9D5-4133-9AC7-483418D94C7E}.Release|x86.Build.0 = Release|Any CPU 49 | {4506B124-94D1-4DA4-A81B-842A2F6B95E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 50 | {4506B124-94D1-4DA4-A81B-842A2F6B95E6}.Debug|Any CPU.Build.0 = Debug|Any CPU 51 | {4506B124-94D1-4DA4-A81B-842A2F6B95E6}.Debug|x64.ActiveCfg = Debug|Any CPU 52 | {4506B124-94D1-4DA4-A81B-842A2F6B95E6}.Debug|x64.Build.0 = Debug|Any CPU 53 | {4506B124-94D1-4DA4-A81B-842A2F6B95E6}.Debug|x86.ActiveCfg = Debug|Any CPU 54 | {4506B124-94D1-4DA4-A81B-842A2F6B95E6}.Debug|x86.Build.0 = Debug|Any CPU 55 | {4506B124-94D1-4DA4-A81B-842A2F6B95E6}.Release|Any CPU.ActiveCfg = Release|Any CPU 56 | {4506B124-94D1-4DA4-A81B-842A2F6B95E6}.Release|Any CPU.Build.0 = Release|Any CPU 57 | {4506B124-94D1-4DA4-A81B-842A2F6B95E6}.Release|x64.ActiveCfg = Release|Any CPU 58 | {4506B124-94D1-4DA4-A81B-842A2F6B95E6}.Release|x64.Build.0 = Release|Any CPU 59 | {4506B124-94D1-4DA4-A81B-842A2F6B95E6}.Release|x86.ActiveCfg = Release|Any CPU 60 | {4506B124-94D1-4DA4-A81B-842A2F6B95E6}.Release|x86.Build.0 = Release|Any CPU 61 | EndGlobalSection 62 | EndGlobal 63 | -------------------------------------------------------------------------------- /templatepack.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Template 5 | $(VersionSuffix) 6 | 2.0.0 7 | $(Version)-$(VersionSuffix) 8 | LICENSE.txt 9 | https://github.com/stavroskasidis/BlazorWithIdentity 10 | https://github.com/stavroskasidis/BlazorWithIdentity/blob/master/README.md 11 | BlazorWithIdentity.Template 12 | Blazor With Identity Template 13 | Stavros Kasidis (AkiraGTX) 14 | Templates to use when creating a blazor hosted application with microsoft's cookie based Identity. 15 | dotnet-new;templates;blazor;blazor-identity;blazor-cookie 16 | 17 | netstandard2.0 18 | 19 | true 20 | false 21 | content 22 | $(NoWarn);NU5128 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /uninstall.ps1: -------------------------------------------------------------------------------- 1 | dotnet new -u BlazorWithIdentity.Template --------------------------------------------------------------------------------