├── .gitattributes ├── .gitignore ├── BlazorAppSecure ├── App.razor ├── BlazorAppSecure.csproj ├── Component │ └── Account │ │ ├── AddRoles.razor │ │ ├── EditUpdateUser.razor │ │ ├── Login.razor │ │ ├── Logout.razor │ │ ├── Register.razor │ │ ├── Users.razor │ │ └── Users.razor.css ├── Layout │ ├── MainLayout.razor │ ├── MainLayout.razor.css │ ├── NavMenu.razor │ └── NavMenu.razor.css ├── Model │ ├── FormResult.cs │ ├── Role.cs │ ├── UserInfo.cs │ └── UserViewModel.cs ├── Pages │ ├── AdminUser.razor │ ├── Counter.razor │ ├── Home.razor │ └── Weather.razor ├── Program.cs ├── Properties │ └── launchSettings.json ├── Sevices │ ├── CustomAuthenticationStateProvider.cs │ ├── CutomHttpHandler.cs │ └── IAccountManagement.cs ├── _Imports.razor └── wwwroot │ ├── appsettings.json │ ├── css │ ├── app.css │ └── bootstrap │ │ ├── bootstrap.min.css │ │ └── bootstrap.min.css.map │ ├── favicon.png │ ├── icon-192.png │ ├── icon-512.png │ ├── index.html │ ├── manifest.webmanifest │ ├── sample-data │ └── weather.json │ ├── service-worker.js │ └── service-worker.published.js ├── idenitywebapiauthenitcation.sln ├── idenitywebapiauthenitcation ├── Controllers │ ├── RoleController.cs │ └── UserController.cs ├── Data │ └── IdentityDbContext.cs ├── Entity │ └── Blog.cs ├── Migrations │ ├── 20240324090534_apiidenity.Designer.cs │ ├── 20240324090534_apiidenity.cs │ └── IdentityDbContextModelSnapshot.cs ├── Model │ ├── AddUserModel.cs │ ├── RoleModel.cs │ └── UserModel.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── Services │ ├── IRoleService.cs │ ├── IUserService.cs │ ├── RoleService.cs │ └── UserService.cs ├── appsettings.Development.json ├── appsettings.json ├── idenitywebapiauthenitcation.csproj ├── idenitywebapiauthenitcation.http └── libman.json └── workload-install.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 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Oo]ut/ 33 | [Ll]og/ 34 | [Ll]ogs/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUnit 49 | *.VisualState.xml 50 | TestResult.xml 51 | nunit-*.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # ASP.NET Scaffolding 67 | ScaffoldingReadMe.txt 68 | 69 | # StyleCop 70 | StyleCopReport.xml 71 | 72 | # Files built by Visual Studio 73 | *_i.c 74 | *_p.c 75 | *_h.h 76 | *.ilk 77 | *.meta 78 | *.obj 79 | *.iobj 80 | *.pch 81 | *.pdb 82 | *.ipdb 83 | *.pgc 84 | *.pgd 85 | *.rsp 86 | *.sbr 87 | *.tlb 88 | *.tli 89 | *.tlh 90 | *.tmp 91 | *.tmp_proj 92 | *_wpftmp.csproj 93 | *.log 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio LightSwitch build output 298 | **/*.HTMLClient/GeneratedArtifacts 299 | **/*.DesktopClient/GeneratedArtifacts 300 | **/*.DesktopClient/ModelManifest.xml 301 | **/*.Server/GeneratedArtifacts 302 | **/*.Server/ModelManifest.xml 303 | _Pvt_Extensions 304 | 305 | # Paket dependency manager 306 | .paket/paket.exe 307 | paket-files/ 308 | 309 | # FAKE - F# Make 310 | .fake/ 311 | 312 | # CodeRush personal settings 313 | .cr/personal 314 | 315 | # Python Tools for Visual Studio (PTVS) 316 | __pycache__/ 317 | *.pyc 318 | 319 | # Cake - Uncomment if you are using it 320 | # tools/** 321 | # !tools/packages.config 322 | 323 | # Tabs Studio 324 | *.tss 325 | 326 | # Telerik's JustMock configuration file 327 | *.jmconfig 328 | 329 | # BizTalk build output 330 | *.btp.cs 331 | *.btm.cs 332 | *.odx.cs 333 | *.xsd.cs 334 | 335 | # OpenCover UI analysis results 336 | OpenCover/ 337 | 338 | # Azure Stream Analytics local run output 339 | ASALocalRun/ 340 | 341 | # MSBuild Binary and Structured Log 342 | *.binlog 343 | 344 | # NVidia Nsight GPU debugger configuration file 345 | *.nvuser 346 | 347 | # MFractors (Xamarin productivity tool) working folder 348 | .mfractor/ 349 | 350 | # Local History for Visual Studio 351 | .localhistory/ 352 | 353 | # BeatPulse healthcheck temp database 354 | healthchecksdb 355 | 356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 357 | MigrationBackup/ 358 | 359 | # Ionide (cross platform F# VS Code tools) working folder 360 | .ionide/ 361 | 362 | # Fody - auto-generated XML schema 363 | FodyWeavers.xsd -------------------------------------------------------------------------------- /BlazorAppSecure/App.razor: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Not found 10 | 11 |

Sorry, there's nothing at this address.

12 |
13 |
14 |
15 |
-------------------------------------------------------------------------------- /BlazorAppSecure/BlazorAppSecure.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | service-worker-assets.js 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /BlazorAppSecure/Component/Account/AddRoles.razor: -------------------------------------------------------------------------------- 1 | @page "/addroles" 2 | @using BlazorAppSecure.Model 3 | @using BlazorAppSecure.Sevices 4 | @using Microsoft.AspNetCore.Authorization 5 | @attribute [Authorize(Roles = "admin")] 6 | @inject IAccountManagement Acct 7 |

AddRoles

8 | 9 | @if(roleList?.Count > 0) 10 | { 11 | 19 | } 20 |

@message

21 | @if (Roles?.Count == 0) 22 | { 23 |
24 | 25 | 26 |
27 | } 28 | else 29 | { 30 | @foreach (var role in Roles) 31 | { 32 | var correntrole = role; 33 |
34 | 35 | 36 |
37 | } 38 | 39 |
40 | 41 | 42 |
43 | 44 |
45 | 46 |
47 | 48 | 49 | } 50 |

@sumbitMesssage

51 | @code { 52 | string sumbitMesssage; 53 | string message; 54 | List Roles = new List(); 55 | List roleList; // api return role list to bind 56 | string NewRole { get; set; } 57 | 58 | protected override void OnInitialized() 59 | { 60 | GetRoles(); 61 | base.OnInitialized(); 62 | } 63 | 64 | private async void GetRoles() 65 | { 66 | var list = await Acct.GetRoles(); 67 | roleList = list.ToList(); 68 | StateHasChanged(); 69 | } 70 | 71 | private void AddRole() 72 | { 73 | if (!string.IsNullOrWhiteSpace(NewRole)) 74 | { 75 | 76 | var isExistRole = Roles.Exists(x => x.Contains(NewRole)); 77 | if (!isExistRole) 78 | { 79 | Roles.Add(NewRole); 80 | message = string.Empty; 81 | } 82 | else 83 | { 84 | message = "already exists"; 85 | } 86 | NewRole = string.Empty; 87 | } 88 | } 89 | 90 | private void RemoveRole(string role) 91 | { 92 | Roles.Remove(role); 93 | } 94 | 95 | private async void SubmitRole() 96 | { 97 | sumbitMesssage = string.Empty; 98 | 99 | var response = await Acct.AddRole(Roles.ToArray()); 100 | 101 | if(response.Succeeded) 102 | { 103 | sumbitMesssage = "successfully saved"; 104 | Roles = new List(); 105 | } 106 | else 107 | { 108 | sumbitMesssage = "falied to saved role"; 109 | } 110 | GetRoles(); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /BlazorAppSecure/Component/Account/EditUpdateUser.razor: -------------------------------------------------------------------------------- 1 | @page "/editUpdateUser/{emailId}" 2 | @using BlazorAppSecure.Model 3 | @using BlazorAppSecure.Sevices 4 | 5 | @inject IAccountManagement Acct 6 | @inject NavigationManager navManger 7 |

EditUpdateUser

8 | 9 | @if (userModel != null) 10 | { 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 |
19 | 20 |
21 | 22 | 23 |
24 | 25 |
26 | 27 | 28 |
29 |
30 | 31 | 32 | @foreach (var role in userModel.Roles) 33 | { 34 | 35 | } 36 | 37 | 38 |
39 | 40 |
41 | } 42 | else 43 | { 44 |

Loading...

45 | } 46 | @code { 47 | 48 | [Parameter] 49 | public string emailId { get; set; } 50 | private UserViewModel userModel = new UserViewModel(); 51 | 52 | private string[] SelectedRoles = new string[] { }; 53 | 54 | protected async override Task OnInitializedAsync() 55 | { 56 | userModel = await Acct.GetUserByEmail(emailId); 57 | SelectedRoles = userModel.Roles.ToArray(); 58 | var roles = await Acct.GetRoles(); 59 | userModel.Roles = roles.Select(x => x.Name).ToList(); 60 | base.OnInitializedAsync(); 61 | } 62 | 63 | private async Task UpdateUser() 64 | { 65 | userModel.Roles = SelectedRoles.ToList(); 66 | if(await Acct.UserUpdate(emailId, userModel)) 67 | { 68 | navManger.NavigateTo("/users"); 69 | } 70 | 71 | var roles = await Acct.GetRoles(); 72 | userModel.Roles = roles.Select(x => x.Name).ToList(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /BlazorAppSecure/Component/Account/Login.razor: -------------------------------------------------------------------------------- 1 | @page "/login" 2 | @using BlazorAppSecure.Sevices 3 | @inject IAccountManagement Acct 4 |

login

5 | 6 | 7 | 8 |
You're logged in as @context.User.Identity?.Name.
9 |
10 | 11 | @if (errors) 12 | { 13 | @foreach (var error in errorList) 14 | { 15 |
@error
16 | } 17 | } 18 |
19 |
20 | 23 | 24 |
25 |
26 | 29 | 30 |
31 |
32 | 33 |
34 |
35 |
36 |
37 | @code { 38 | private bool success, errors; 39 | private string email = string.Empty; 40 | private string password = string.Empty; 41 | private string[] errorList = []; 42 | 43 | public async Task DoLoginAsync() 44 | { 45 | success = errors = false; 46 | errorList = []; 47 | 48 | if (string.IsNullOrWhiteSpace(email)) 49 | { 50 | errors = true; 51 | errorList = ["Email is required."]; 52 | 53 | return; 54 | } 55 | 56 | if (string.IsNullOrWhiteSpace(password)) 57 | { 58 | errors = true; 59 | errorList = ["Password is required."]; 60 | 61 | return; 62 | } 63 | 64 | var result = await Acct.LoginAsync(email, password); 65 | 66 | if (result.Succeeded) 67 | { 68 | success = true; 69 | email = password = string.Empty; 70 | } 71 | else 72 | { 73 | errors = true; 74 | errorList = result.ErrorList; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /BlazorAppSecure/Component/Account/Logout.razor: -------------------------------------------------------------------------------- 1 | @page "/logout" 2 | @using BlazorAppSecure.Sevices 3 | @inject IAccountManagement Acct 4 | 5 |

Logout

6 | 7 | 8 |
Logging you out...
9 |
10 | 11 |
You're logged out. Log in.
12 |
13 |
14 | 15 | 16 | @code { 17 | 18 | private AuthorizeView? authView; 19 | 20 | protected override async Task OnInitializedAsync() 21 | { 22 | if(await Acct.CheckAuthenticatedAsync()) 23 | { 24 | await Acct.LogoutAsync(); 25 | } 26 | await base.OnInitializedAsync(); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /BlazorAppSecure/Component/Account/Register.razor: -------------------------------------------------------------------------------- 1 | @page "/register" 2 | @using BlazorAppSecure.Sevices 3 | 4 | @inject IAccountManagement Acct 5 | 6 |

Register

7 | 8 | 9 | 10 |
You're already logged in as @context.User.Identity?.Name.
11 |
12 | 13 | @if (success) 14 | { 15 |
You successfully registered. Now you can login.
16 | } 17 | else 18 | { 19 | if (errors) 20 | { 21 | foreach (var error in errorList) 22 | { 23 |
@error
24 | } 25 | } 26 |
27 |
28 | 31 | 32 |
33 |
34 | 37 |
38 |
39 |
40 | 43 | 44 |
45 |
46 | 47 |
48 |
49 | } 50 |
51 |
52 | 53 | @code { 54 | private bool success, errors; 55 | private string email = string.Empty; 56 | private string password = string.Empty; 57 | private string confirmPassword = string.Empty; 58 | private string[] errorList = []; 59 | 60 | public async Task DoRegisterAsync() 61 | { 62 | success = errors = false; 63 | errorList = []; 64 | 65 | if (string.IsNullOrWhiteSpace(email)) 66 | { 67 | errors = true; 68 | errorList = ["Email is required."]; 69 | 70 | return; 71 | } 72 | 73 | if (string.IsNullOrWhiteSpace(password)) 74 | { 75 | errors = true; 76 | errorList = ["Password is required."]; 77 | 78 | return; 79 | } 80 | 81 | if (string.IsNullOrWhiteSpace(confirmPassword)) 82 | { 83 | errors = true; 84 | errorList = ["Please confirm your password."]; 85 | 86 | return; 87 | } 88 | 89 | if (password != confirmPassword) 90 | { 91 | errors = true; 92 | errorList = ["Passwords don't match."]; 93 | 94 | return; 95 | } 96 | 97 | var result = await Acct.RegisterAsync(email, password); 98 | 99 | if (result.Succeeded) 100 | { 101 | success = true; 102 | email = password = confirmPassword = string.Empty; 103 | } 104 | else 105 | { 106 | errors = true; 107 | errorList = result.ErrorList; 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /BlazorAppSecure/Component/Account/Users.razor: -------------------------------------------------------------------------------- 1 | @page "/users" 2 | @using BlazorAppSecure.Model 3 | @using BlazorAppSecure.Sevices 4 | @using Microsoft.AspNetCore.Components.QuickGrid 5 | 6 | @inject IAccountManagement Acct 7 | @inject NavigationManager Navigation 8 |

Users

9 | 10 |
11 | 12 | 13 | 14 | 15 |
16 | 17 | @if (context.Roles != null && context.Roles?.Count > 0 ) 18 | { 19 |
    20 | @foreach (var item in context.Roles) 21 | { 22 |
  • 23 | @item 24 |
  • 25 | } 26 |
27 | } 28 | 29 | else 30 | { 31 | ------ 32 | } 33 |
34 |
35 |
36 | 37 | 38 | 39 | 42 | 45 | 46 |
47 |
48 | 49 | @code { 50 | private IQueryable userList; 51 | 52 | protected override async Task OnInitializedAsync() 53 | { 54 | var users = await Acct.GetUsers(); 55 | userList = users.ToList().AsQueryable(); 56 | base.OnInitializedAsync(); 57 | } 58 | 59 | void Edit(UserViewModel p) 60 | { 61 | Navigation.NavigateTo($"editupdateuser/{p.Email}"); 62 | } 63 | async void Delete(UserViewModel p) 64 | { 65 | if(await Acct.Delete(p.Email)) 66 | { 67 | var users = await Acct.GetUsers(); 68 | userList = users.ToList().AsQueryable(); 69 | StateHasChanged(); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /BlazorAppSecure/Component/Account/Users.razor.css: -------------------------------------------------------------------------------- 1 | /* Fix height and enable scrolling */ 2 | .grid { 3 | height: 25rem; 4 | overflow-y: auto; 5 | } 6 | 7 | .grid ::deep table { 8 | min-width: 100%; 9 | } 10 | 11 | /* Sticky header while scrolling */ 12 | ::deep thead { 13 | position: sticky; 14 | top: 0; 15 | background-color: #d8d8d8; 16 | outline: 1px solid gray; 17 | z-index: 1; 18 | } 19 | 20 | /* For virtualized grids, it's essential that all rows have the same known height */ 21 | ::deep tr { 22 | height: 30px; 23 | border-bottom: 0.5px solid silver; 24 | } 25 | 26 | ::deep tbody td { 27 | white-space: nowrap; 28 | overflow: hidden; 29 | max-width: 0; 30 | text-overflow: ellipsis; 31 | } 32 | -------------------------------------------------------------------------------- /BlazorAppSecure/Layout/MainLayout.razor: -------------------------------------------------------------------------------- 1 | @inherits LayoutComponentBase 2 |
3 | 6 | 7 |
8 | 9 |
10 | 11 | 12 | Logged in as @context.User.Identity?.Name. Logout 13 | 14 | 15 | Login 16 | Register 17 | 18 | 19 |
20 | 21 |
22 | @Body 23 |
24 |
25 |
26 | -------------------------------------------------------------------------------- /BlazorAppSecure/Layout/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 { 41 | justify-content: space-between; 42 | } 43 | 44 | .top-row ::deep a, .top-row ::deep .btn-link { 45 | margin-left: 0; 46 | } 47 | } 48 | 49 | @media (min-width: 641px) { 50 | .page { 51 | flex-direction: row; 52 | } 53 | 54 | .sidebar { 55 | width: 250px; 56 | height: 100vh; 57 | position: sticky; 58 | top: 0; 59 | } 60 | 61 | .top-row { 62 | position: sticky; 63 | top: 0; 64 | z-index: 1; 65 | } 66 | 67 | .top-row.auth ::deep a:first-child { 68 | flex: 1; 69 | text-align: right; 70 | width: 0; 71 | } 72 | 73 | .top-row, article { 74 | padding-left: 2rem !important; 75 | padding-right: 1.5rem !important; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /BlazorAppSecure/Layout/NavMenu.razor: -------------------------------------------------------------------------------- 1 |  9 | 10 | 47 | 48 | @code { 49 | private bool collapseNavMenu = true; 50 | 51 | private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null; 52 | 53 | private void ToggleNavMenu() 54 | { 55 | collapseNavMenu = !collapseNavMenu; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /BlazorAppSecure/Layout/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 | .bi { 15 | display: inline-block; 16 | position: relative; 17 | width: 1.25rem; 18 | height: 1.25rem; 19 | margin-right: 0.75rem; 20 | top: -1px; 21 | background-size: cover; 22 | } 23 | 24 | .bi-house-door-fill-nav-menu { 25 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E"); 26 | } 27 | 28 | .bi-plus-square-fill-nav-menu { 29 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z'/%3E%3C/svg%3E"); 30 | } 31 | 32 | .bi-list-nested-nav-menu { 33 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E"); 34 | } 35 | 36 | .nav-item { 37 | font-size: 0.9rem; 38 | padding-bottom: 0.5rem; 39 | } 40 | 41 | .nav-item:first-of-type { 42 | padding-top: 1rem; 43 | } 44 | 45 | .nav-item:last-of-type { 46 | padding-bottom: 1rem; 47 | } 48 | 49 | .nav-item ::deep a { 50 | color: #d7d7d7; 51 | border-radius: 4px; 52 | height: 3rem; 53 | display: flex; 54 | align-items: center; 55 | line-height: 3rem; 56 | } 57 | 58 | .nav-item ::deep a.active { 59 | background-color: rgba(255,255,255,0.37); 60 | color: white; 61 | } 62 | 63 | .nav-item ::deep a:hover { 64 | background-color: rgba(255,255,255,0.1); 65 | color: white; 66 | } 67 | 68 | @media (min-width: 641px) { 69 | .navbar-toggler { 70 | display: none; 71 | } 72 | 73 | .collapse { 74 | /* Never collapse the sidebar for wide screens */ 75 | display: block; 76 | } 77 | 78 | .nav-scrollable { 79 | /* Allow sidebar to scroll for tall menus */ 80 | height: calc(100vh - 3.5rem); 81 | overflow-y: auto; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /BlazorAppSecure/Model/FormResult.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorAppSecure.Model 2 | { 3 | public class FormResult 4 | { 5 | public bool Succeeded { get; set; } 6 | public string[] ErrorList { get; set; } = []; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /BlazorAppSecure/Model/Role.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorAppSecure.Model 2 | { 3 | public class Role 4 | { 5 | public string Id { get; set; } 6 | public string Name { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /BlazorAppSecure/Model/UserInfo.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorAppSecure.Model 2 | { 3 | public class UserInfo 4 | { 5 | public string Email { get; set; } = string.Empty; 6 | public bool IsEmailConfirmed { get; set; } 7 | public Dictionary Claims { get; set; } = []; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /BlazorAppSecure/Model/UserViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorAppSecure.Model 2 | { 3 | public class UserViewModel 4 | { 5 | public Guid Id { get; set; } 6 | public string UserName { get; set; } 7 | public string Email { get; set; } 8 | public string PhoneNumber { get; set; } 9 | 10 | public List Roles { get; set; } = new List(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /BlazorAppSecure/Pages/AdminUser.razor: -------------------------------------------------------------------------------- 1 | @page "/adminUser" 2 | @using Microsoft.AspNetCore.Authorization 3 | @attribute [Authorize(Roles = "admin")] 4 |

AdminUser

5 | 6 | @code { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /BlazorAppSecure/Pages/Counter.razor: -------------------------------------------------------------------------------- 1 | @page "/counter" 2 | 3 | Counter 4 | 5 |

Counter

6 | 7 |

Current count: @currentCount

8 | 9 | 10 | 11 | @code { 12 | private int currentCount = 0; 13 | 14 | private void IncrementCount() 15 | { 16 | currentCount++; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /BlazorAppSecure/Pages/Home.razor: -------------------------------------------------------------------------------- 1 | @page "/" 2 | 3 | Home 4 | 5 |

Hello, world!

6 | 7 | Welcome to your new app. 8 | -------------------------------------------------------------------------------- /BlazorAppSecure/Pages/Weather.razor: -------------------------------------------------------------------------------- 1 | @page "/weather" 2 | @inject HttpClient Http 3 | 4 | Weather 5 | 6 |

Weather

7 | 8 |

This component demonstrates fetching data from the server.

9 | 10 | @if (forecasts == null) 11 | { 12 |

Loading...

13 | } 14 | else 15 | { 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | @foreach (var forecast in forecasts) 27 | { 28 | 29 | 30 | 31 | 32 | 33 | 34 | } 35 | 36 |
DateTemp. (C)Temp. (F)Summary
@forecast.Date.ToShortDateString()@forecast.TemperatureC@forecast.TemperatureF@forecast.Summary
37 | } 38 | 39 | @code { 40 | private WeatherForecast[]? forecasts; 41 | 42 | protected override async Task OnInitializedAsync() 43 | { 44 | forecasts = await Http.GetFromJsonAsync("sample-data/weather.json"); 45 | } 46 | 47 | public class WeatherForecast 48 | { 49 | public DateOnly Date { get; set; } 50 | 51 | public int TemperatureC { get; set; } 52 | 53 | public string? Summary { get; set; } 54 | 55 | public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /BlazorAppSecure/Program.cs: -------------------------------------------------------------------------------- 1 | using BlazorAppSecure; 2 | using BlazorAppSecure.Sevices; 3 | using Microsoft.AspNetCore.Components.Authorization; 4 | using Microsoft.AspNetCore.Components.Web; 5 | using Microsoft.AspNetCore.Components.WebAssembly.Hosting; 6 | 7 | var builder = WebAssemblyHostBuilder.CreateDefault(args); 8 | 9 | builder.Services.AddAuthorizationCore(); 10 | builder.RootComponents.Add("#app"); 11 | builder.RootComponents.Add("head::after"); 12 | 13 | builder.Services.AddTransient(); 14 | builder.Services.AddScoped(); 15 | builder.Services.AddScoped(sp => (IAccountManagement)sp.GetRequiredService()); 16 | 17 | builder.Services.AddScoped(sp => new HttpClient { BaseAddress = 18 | new Uri(builder.Configuration["FrontendUrl"] ?? "https://localhost:5002") }); 19 | 20 | 21 | builder.Services.AddHttpClient("Auth", opt => opt.BaseAddress = 22 | new Uri(builder.Configuration["BackendUrl"] ?? "https://localhost:7030")) 23 | .AddHttpMessageHandler(); 24 | 25 | await builder.Build().RunAsync(); 26 | -------------------------------------------------------------------------------- /BlazorAppSecure/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:8461", 8 | "sslPort": 44370 9 | } 10 | }, 11 | "profiles": { 12 | "http": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 17 | "applicationUrl": "http://localhost:5187", 18 | "environmentVariables": { 19 | "ASPNETCORE_ENVIRONMENT": "Development" 20 | } 21 | }, 22 | "https": { 23 | "commandName": "Project", 24 | "dotnetRunMessages": true, 25 | "launchBrowser": true, 26 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 27 | "applicationUrl": "https://localhost:7195;http://localhost:5187", 28 | "environmentVariables": { 29 | "ASPNETCORE_ENVIRONMENT": "Development" 30 | } 31 | }, 32 | "IIS Express": { 33 | "commandName": "IISExpress", 34 | "launchBrowser": true, 35 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 36 | "environmentVariables": { 37 | "ASPNETCORE_ENVIRONMENT": "Development" 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /BlazorAppSecure/Sevices/CustomAuthenticationStateProvider.cs: -------------------------------------------------------------------------------- 1 | using BlazorAppSecure.Model; 2 | using Microsoft.AspNetCore.Components.Authorization; 3 | using System.Net.Http; 4 | using System.Net.Http.Json; 5 | using System.Security.Claims; 6 | using System.Text; 7 | using System.Text.Json; 8 | 9 | namespace BlazorAppSecure.Sevices 10 | { 11 | public class CustomAuthenticationStateProvider : AuthenticationStateProvider, IAccountManagement 12 | { 13 | private bool _authenticated = false; 14 | 15 | private readonly ClaimsPrincipal Unauthenticated = 16 | new(new ClaimsIdentity()); 17 | 18 | private readonly HttpClient _httpClient; 19 | 20 | 21 | private readonly JsonSerializerOptions jsonSerializerOptions = 22 | new() 23 | { 24 | PropertyNamingPolicy = JsonNamingPolicy.CamelCase, 25 | }; 26 | public CustomAuthenticationStateProvider(IHttpClientFactory httpClientFactory) 27 | { 28 | _httpClient = httpClientFactory.CreateClient("Auth"); 29 | } 30 | 31 | public override async Task GetAuthenticationStateAsync() 32 | { 33 | _authenticated = false; 34 | 35 | // default to not authenticated 36 | var user = Unauthenticated; 37 | 38 | try 39 | { 40 | var userResponse = await _httpClient.GetAsync("manage/info"); 41 | 42 | userResponse.EnsureSuccessStatusCode(); 43 | 44 | var userJson = await userResponse.Content.ReadAsStringAsync(); 45 | var userInfo = JsonSerializer.Deserialize(userJson, jsonSerializerOptions); 46 | 47 | if (userInfo != null) 48 | { 49 | var claims = new List 50 | { 51 | new(ClaimTypes.Name, userInfo.Email), 52 | new(ClaimTypes.Email, userInfo.Email) 53 | }; 54 | 55 | claims.AddRange( 56 | userInfo.Claims.Where(c => c.Key != ClaimTypes.Name && c.Key != ClaimTypes.Email) 57 | .Select(c => new Claim(c.Key, c.Value))); 58 | 59 | var rolesResponse = await _httpClient.GetAsync($"api/Role/GetuserRole?userEmail={userInfo.Email}"); 60 | 61 | rolesResponse.EnsureSuccessStatusCode(); 62 | 63 | var rolesJson = await rolesResponse.Content.ReadAsStringAsync(); 64 | 65 | var roles = JsonSerializer.Deserialize(rolesJson, jsonSerializerOptions); 66 | if (roles != null && roles?.Length > 0) 67 | { 68 | foreach (var role in roles) 69 | { 70 | claims.Add(new(ClaimTypes.Role, role)); 71 | } 72 | } 73 | 74 | var id = new ClaimsIdentity(claims, nameof(CustomAuthenticationStateProvider)); 75 | 76 | user = new ClaimsPrincipal(id); 77 | 78 | _authenticated = true; 79 | 80 | } 81 | } 82 | catch (Exception ex) 83 | { 84 | 85 | 86 | } 87 | 88 | return new AuthenticationState(user); 89 | 90 | } 91 | 92 | public async Task RegisterAsync(string email, string password) 93 | { 94 | string[] defaultDetail = ["An unknown error prevented registration from succeeding."]; 95 | 96 | try 97 | { 98 | 99 | var result = await _httpClient.PostAsJsonAsync("register", 100 | new { email, password }); 101 | if (result.IsSuccessStatusCode) 102 | { 103 | return new FormResult { Succeeded = true }; 104 | } 105 | 106 | var details = await result.Content.ReadAsStringAsync(); 107 | var problemDetails = JsonDocument.Parse(details); 108 | var errors = new List(); 109 | var errorList = problemDetails.RootElement.GetProperty("errors"); 110 | 111 | foreach (var errorEntry in errorList.EnumerateObject()) 112 | { 113 | if (errorEntry.Value.ValueKind == JsonValueKind.String) 114 | { 115 | errors.Add(errorEntry.Value.GetString()!); 116 | } 117 | else if (errorEntry.Value.ValueKind == JsonValueKind.Array) 118 | { 119 | errors.AddRange( 120 | errorEntry.Value.EnumerateArray().Select( 121 | e => e.GetString() ?? string.Empty) 122 | .Where(e => !string.IsNullOrEmpty(e))); 123 | } 124 | } 125 | return new FormResult 126 | { 127 | Succeeded = false, 128 | ErrorList = problemDetails == null ? defaultDetail : [.. errors] 129 | }; 130 | 131 | } 132 | catch (Exception ex) 133 | { 134 | 135 | throw; 136 | } 137 | } 138 | 139 | public async Task LoginAsync(string email, string password) 140 | { 141 | try 142 | { 143 | var result = await _httpClient.PostAsJsonAsync( 144 | "login?useCookies=true", new 145 | { 146 | email, 147 | password 148 | }); 149 | 150 | if (result.IsSuccessStatusCode) 151 | { 152 | NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); 153 | return new FormResult { Succeeded = true }; 154 | } 155 | } 156 | catch (Exception ex) 157 | { 158 | 159 | throw; 160 | } 161 | 162 | return new FormResult 163 | { 164 | Succeeded = false, 165 | ErrorList = ["Invalid email and/or password."] 166 | }; 167 | } 168 | 169 | public async Task LogoutAsync() 170 | { 171 | const string Empty = "{}"; 172 | var emptyContent = new StringContent(Empty, Encoding.UTF8, "application/json"); 173 | 174 | await _httpClient.PostAsync("api/user/Logout", emptyContent); 175 | NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); 176 | 177 | } 178 | 179 | public async Task CheckAuthenticatedAsync() 180 | { 181 | await GetAuthenticationStateAsync(); 182 | return _authenticated; 183 | } 184 | 185 | public async Task> GetRoles() 186 | { 187 | try 188 | { 189 | var result = await _httpClient.GetAsync("api/Role/GetRoles"); 190 | var resposne = await result.Content.ReadAsStringAsync(); 191 | var rolelist = JsonSerializer.Deserialize>(resposne, jsonSerializerOptions); 192 | if (result.IsSuccessStatusCode) 193 | { 194 | return rolelist; 195 | } 196 | } 197 | catch (Exception ex) 198 | { 199 | 200 | 201 | } 202 | 203 | return new List(); 204 | 205 | } 206 | 207 | public async Task AddRole(string[] roles) 208 | { 209 | try 210 | { 211 | var content = new StringContent(JsonSerializer.Serialize(roles), Encoding.UTF8, "application/json"); 212 | var result = await _httpClient.PostAsync("api/Role/addRoles", content); 213 | 214 | if (result.IsSuccessStatusCode) 215 | { 216 | return new FormResult { Succeeded = true }; 217 | } 218 | 219 | 220 | } 221 | catch (Exception ex) 222 | { 223 | 224 | 225 | } 226 | return new FormResult 227 | { 228 | Succeeded = false, 229 | ErrorList = ["api has some issue"] 230 | }; 231 | } 232 | 233 | public async Task GetUsers() 234 | { 235 | try 236 | { 237 | var result = await _httpClient.GetAsync("api/User"); 238 | var resposne = await result.Content.ReadAsStringAsync(); 239 | var userlist = JsonSerializer.Deserialize(resposne, jsonSerializerOptions); 240 | if (result.IsSuccessStatusCode) 241 | { 242 | return userlist; 243 | } 244 | } 245 | catch (Exception ex) 246 | { 247 | 248 | 249 | } 250 | 251 | return null; 252 | } 253 | 254 | public async Task GetUserByEmail(string userEmailId) 255 | { 256 | try 257 | { 258 | var result = await _httpClient.GetAsync($"api/User/{userEmailId}"); 259 | var resposne = await result.Content.ReadAsStringAsync(); 260 | var user = JsonSerializer.Deserialize(resposne, jsonSerializerOptions); 261 | if (result.IsSuccessStatusCode) 262 | { 263 | return user; 264 | } 265 | } 266 | catch (Exception ex) 267 | { 268 | 269 | 270 | } 271 | 272 | return null; 273 | } 274 | 275 | public async Task UserUpdate(string userEmailId, UserViewModel user) 276 | { 277 | try 278 | { 279 | var content = new StringContent(JsonSerializer.Serialize(user), 280 | Encoding.UTF8, "application/json"); 281 | var response = await _httpClient.PutAsync($"api/User/{userEmailId}", content); 282 | return response.IsSuccessStatusCode; 283 | } 284 | catch (Exception ex) 285 | { 286 | 287 | 288 | } 289 | return false; 290 | } 291 | 292 | public async Task Delete(string userEmailId) 293 | { 294 | try 295 | { 296 | var result = await _httpClient.DeleteAsync($"api/User/{userEmailId}"); 297 | return result.IsSuccessStatusCode; 298 | 299 | } 300 | catch (Exception ex) 301 | { 302 | 303 | 304 | } 305 | 306 | return false; 307 | } 308 | } 309 | } 310 | -------------------------------------------------------------------------------- /BlazorAppSecure/Sevices/CutomHttpHandler.cs: -------------------------------------------------------------------------------- 1 |  2 | using Microsoft.AspNetCore.Components.WebAssembly.Http; 3 | 4 | namespace BlazorAppSecure.Sevices 5 | { 6 | public class CutomHttpHandler : DelegatingHandler 7 | { 8 | protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 9 | { 10 | request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include); 11 | request.Headers.Add("X-Requested-With", ["XMLHttpRequest"]); 12 | return base.SendAsync(request, cancellationToken); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /BlazorAppSecure/Sevices/IAccountManagement.cs: -------------------------------------------------------------------------------- 1 | using BlazorAppSecure.Model; 2 | using System.Data; 3 | 4 | namespace BlazorAppSecure.Sevices 5 | { 6 | public interface IAccountManagement 7 | { 8 | public Task RegisterAsync(string email, string password); 9 | 10 | public Task LoginAsync(string email, string password); 11 | 12 | public Task LogoutAsync(); 13 | 14 | public Task CheckAuthenticatedAsync(); 15 | 16 | public Task> GetRoles(); 17 | 18 | public Task AddRole(string[] roles); 19 | 20 | public Task GetUsers(); 21 | 22 | public Task GetUserByEmail(string userEmailId); 23 | 24 | public Task UserUpdate(string userEmailId, UserViewModel user); 25 | 26 | public Task Delete(string userEmailId); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /BlazorAppSecure/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using Microsoft.AspNetCore.Components.Web.Virtualization 7 | @using Microsoft.AspNetCore.Components.WebAssembly.Http 8 | @using Microsoft.JSInterop 9 | @using BlazorAppSecure 10 | @using BlazorAppSecure.Layout 11 | @using Microsoft.AspNetCore.Components.Authorization 12 | -------------------------------------------------------------------------------- /BlazorAppSecure/wwwroot/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "BackendUrl": "https://localhost:7239", 3 | "FrontendUrl": "https://localhost:7195" 4 | } 5 | -------------------------------------------------------------------------------- /BlazorAppSecure/wwwroot/css/app.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 3 | } 4 | 5 | h1:focus { 6 | outline: none; 7 | } 8 | 9 | a, .btn-link { 10 | color: #0071c1; 11 | } 12 | 13 | .btn-primary { 14 | color: #fff; 15 | background-color: #1b6ec2; 16 | border-color: #1861ac; 17 | } 18 | 19 | .btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus { 20 | box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb; 21 | } 22 | 23 | .content { 24 | padding-top: 1.1rem; 25 | } 26 | 27 | .valid.modified:not([type=checkbox]) { 28 | outline: 1px solid #26b050; 29 | } 30 | 31 | .invalid { 32 | outline: 1px solid red; 33 | } 34 | 35 | .validation-message { 36 | color: red; 37 | } 38 | 39 | #blazor-error-ui { 40 | background: lightyellow; 41 | bottom: 0; 42 | box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); 43 | display: none; 44 | left: 0; 45 | padding: 0.6rem 1.25rem 0.7rem 1.25rem; 46 | position: fixed; 47 | width: 100%; 48 | z-index: 1000; 49 | } 50 | 51 | #blazor-error-ui .dismiss { 52 | cursor: pointer; 53 | position: absolute; 54 | right: 0.75rem; 55 | top: 0.5rem; 56 | } 57 | 58 | .blazor-error-boundary { 59 | background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121; 60 | padding: 1rem 1rem 1rem 3.7rem; 61 | color: white; 62 | } 63 | 64 | .blazor-error-boundary::after { 65 | content: "An error has occurred." 66 | } 67 | 68 | .loading-progress { 69 | position: relative; 70 | display: block; 71 | width: 8rem; 72 | height: 8rem; 73 | margin: 20vh auto 1rem auto; 74 | } 75 | 76 | .loading-progress circle { 77 | fill: none; 78 | stroke: #e0e0e0; 79 | stroke-width: 0.6rem; 80 | transform-origin: 50% 50%; 81 | transform: rotate(-90deg); 82 | } 83 | 84 | .loading-progress circle:last-child { 85 | stroke: #1b6ec2; 86 | stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%; 87 | transition: stroke-dasharray 0.05s ease-in-out; 88 | } 89 | 90 | .loading-progress-text { 91 | position: absolute; 92 | text-align: center; 93 | font-weight: bold; 94 | inset: calc(20vh + 3.25rem) 0 auto 0.2rem; 95 | } 96 | 97 | .loading-progress-text:after { 98 | content: var(--blazor-load-percentage-text, "Loading"); 99 | } 100 | 101 | code { 102 | color: #c02d76; 103 | } 104 | 105 | label { 106 | font-weight: bold; 107 | color: darkblue; 108 | margin: 3px; 109 | } 110 | 111 | input { 112 | margin: 3px; 113 | } 114 | 115 | .flex-outer div { 116 | display: flex; 117 | flex-wrap: wrap; 118 | align-items: center; 119 | } 120 | 121 | .flex-outer div:last-child { 122 | margin-top: 20px; 123 | } 124 | 125 | .flex-outer div label, 126 | .flex-outer div input { 127 | flex: 1 0 120px; 128 | max-width: 220px; 129 | } 130 | 131 | .flex-outer div label + * { 132 | flex: 1 0 120px; 133 | } 134 | 135 | -------------------------------------------------------------------------------- /BlazorAppSecure/wwwroot/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kartik786-git/UserManagementSystem-blazor-webapi/478f4399746a3f8e4196fde2c357fbe3201ec147/BlazorAppSecure/wwwroot/favicon.png -------------------------------------------------------------------------------- /BlazorAppSecure/wwwroot/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kartik786-git/UserManagementSystem-blazor-webapi/478f4399746a3f8e4196fde2c357fbe3201ec147/BlazorAppSecure/wwwroot/icon-192.png -------------------------------------------------------------------------------- /BlazorAppSecure/wwwroot/icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kartik786-git/UserManagementSystem-blazor-webapi/478f4399746a3f8e4196fde2c357fbe3201ec147/BlazorAppSecure/wwwroot/icon-512.png -------------------------------------------------------------------------------- /BlazorAppSecure/wwwroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | BlazorAppSecure 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 |
25 |
26 | 27 |
28 | An unhandled error has occurred. 29 | Reload 30 | 🗙 31 |
32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /BlazorAppSecure/wwwroot/manifest.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "BlazorAppSecure", 3 | "short_name": "BlazorAppSecure", 4 | "id": "./", 5 | "start_url": "./", 6 | "display": "standalone", 7 | "background_color": "#ffffff", 8 | "theme_color": "#03173d", 9 | "prefer_related_applications": false, 10 | "icons": [ 11 | { 12 | "src": "icon-512.png", 13 | "type": "image/png", 14 | "sizes": "512x512" 15 | }, 16 | { 17 | "src": "icon-192.png", 18 | "type": "image/png", 19 | "sizes": "192x192" 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /BlazorAppSecure/wwwroot/sample-data/weather.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "date": "2022-01-06", 4 | "temperatureC": 1, 5 | "summary": "Freezing" 6 | }, 7 | { 8 | "date": "2022-01-07", 9 | "temperatureC": 14, 10 | "summary": "Bracing" 11 | }, 12 | { 13 | "date": "2022-01-08", 14 | "temperatureC": -13, 15 | "summary": "Freezing" 16 | }, 17 | { 18 | "date": "2022-01-09", 19 | "temperatureC": -16, 20 | "summary": "Balmy" 21 | }, 22 | { 23 | "date": "2022-01-10", 24 | "temperatureC": -2, 25 | "summary": "Chilly" 26 | } 27 | ] 28 | -------------------------------------------------------------------------------- /BlazorAppSecure/wwwroot/service-worker.js: -------------------------------------------------------------------------------- 1 | // In development, always fetch from the network and do not enable offline support. 2 | // This is because caching would make development more difficult (changes would not 3 | // be reflected on the first load after each change). 4 | self.addEventListener('fetch', () => { }); 5 | -------------------------------------------------------------------------------- /BlazorAppSecure/wwwroot/service-worker.published.js: -------------------------------------------------------------------------------- 1 | // Caution! Be sure you understand the caveats before publishing an application with 2 | // offline support. See https://aka.ms/blazor-offline-considerations 3 | 4 | self.importScripts('./service-worker-assets.js'); 5 | self.addEventListener('install', event => event.waitUntil(onInstall(event))); 6 | self.addEventListener('activate', event => event.waitUntil(onActivate(event))); 7 | self.addEventListener('fetch', event => event.respondWith(onFetch(event))); 8 | 9 | const cacheNamePrefix = 'offline-cache-'; 10 | const cacheName = `${cacheNamePrefix}${self.assetsManifest.version}`; 11 | const offlineAssetsInclude = [ /\.dll$/, /\.pdb$/, /\.wasm/, /\.html/, /\.js$/, /\.json$/, /\.css$/, /\.woff$/, /\.png$/, /\.jpe?g$/, /\.gif$/, /\.ico$/, /\.blat$/, /\.dat$/ ]; 12 | const offlineAssetsExclude = [ /^service-worker\.js$/ ]; 13 | 14 | // Replace with your base path if you are hosting on a subfolder. Ensure there is a trailing '/'. 15 | const base = "/"; 16 | const baseUrl = new URL(base, self.origin); 17 | const manifestUrlList = self.assetsManifest.assets.map(asset => new URL(asset.url, baseUrl).href); 18 | 19 | async function onInstall(event) { 20 | console.info('Service worker: Install'); 21 | 22 | // Fetch and cache all matching items from the assets manifest 23 | const assetsRequests = self.assetsManifest.assets 24 | .filter(asset => offlineAssetsInclude.some(pattern => pattern.test(asset.url))) 25 | .filter(asset => !offlineAssetsExclude.some(pattern => pattern.test(asset.url))) 26 | .map(asset => new Request(asset.url, { integrity: asset.hash, cache: 'no-cache' })); 27 | await caches.open(cacheName).then(cache => cache.addAll(assetsRequests)); 28 | } 29 | 30 | async function onActivate(event) { 31 | console.info('Service worker: Activate'); 32 | 33 | // Delete unused caches 34 | const cacheKeys = await caches.keys(); 35 | await Promise.all(cacheKeys 36 | .filter(key => key.startsWith(cacheNamePrefix) && key !== cacheName) 37 | .map(key => caches.delete(key))); 38 | } 39 | 40 | async function onFetch(event) { 41 | let cachedResponse = null; 42 | if (event.request.method === 'GET') { 43 | // For all navigation requests, try to serve index.html from cache, 44 | // unless that request is for an offline resource. 45 | // If you need some URLs to be server-rendered, edit the following check to exclude those URLs 46 | const shouldServeIndexHtml = event.request.mode === 'navigate' 47 | && !manifestUrlList.some(url => url === event.request.url); 48 | 49 | const request = shouldServeIndexHtml ? 'index.html' : event.request; 50 | const cache = await caches.open(cacheName); 51 | cachedResponse = await cache.match(request); 52 | } 53 | 54 | return cachedResponse || fetch(event.request); 55 | } 56 | -------------------------------------------------------------------------------- /idenitywebapiauthenitcation.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.10.34707.107 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "idenitywebapiauthenitcation", "idenitywebapiauthenitcation\idenitywebapiauthenitcation.csproj", "{85F23533-35DF-41D9-ABAD-508580109F34}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorAppSecure", "BlazorAppSecure\BlazorAppSecure.csproj", "{8AC27660-22BD-47C2-BC9C-7B8C427B3A8C}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {85F23533-35DF-41D9-ABAD-508580109F34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {85F23533-35DF-41D9-ABAD-508580109F34}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {85F23533-35DF-41D9-ABAD-508580109F34}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {85F23533-35DF-41D9-ABAD-508580109F34}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {8AC27660-22BD-47C2-BC9C-7B8C427B3A8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {8AC27660-22BD-47C2-BC9C-7B8C427B3A8C}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {8AC27660-22BD-47C2-BC9C-7B8C427B3A8C}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {8AC27660-22BD-47C2-BC9C-7B8C427B3A8C}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {AEB7C419-34E5-45B7-8143-56EF7D825BFE} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /idenitywebapiauthenitcation/Controllers/RoleController.cs: -------------------------------------------------------------------------------- 1 | using idenitywebapiauthenitcation.Model; 2 | using idenitywebapiauthenitcation.Services; 3 | using Microsoft.AspNetCore.Authorization; 4 | using Microsoft.AspNetCore.Http; 5 | using Microsoft.AspNetCore.Mvc; 6 | using System.Net; 7 | 8 | namespace idenitywebapiauthenitcation.Controllers 9 | { 10 | [Route("api/[controller]")] 11 | [ApiController] 12 | public class RoleController : ControllerBase 13 | { 14 | private readonly IRoleService _roleService; 15 | 16 | public RoleController(IRoleService roleService) 17 | { 18 | _roleService = roleService; 19 | } 20 | 21 | [Authorize(Roles = "admin")] 22 | [HttpGet("GetRoles")] 23 | public async Task GetRoles() 24 | { 25 | 26 | var list = await _roleService.GetRolesAsync(); 27 | return Ok(list); 28 | } 29 | 30 | [Authorize] 31 | [HttpGet("GetUserRole")] 32 | public async Task GetuserRole(string userEmail) 33 | { 34 | var userClaims = await _roleService.GetUserRolesAsync(userEmail); 35 | return Ok(userClaims); 36 | 37 | } 38 | 39 | [Authorize(Roles = "admin")] 40 | [HttpPost("addRoles")] 41 | public async Task AddRole(string[] roles) 42 | { 43 | var userrole = await _roleService.AddRolesAsync(roles); 44 | if (userrole.Count == 0) 45 | { 46 | return BadRequest(); 47 | } 48 | return Ok(userrole); 49 | } 50 | 51 | [Authorize(Roles = "admin")] 52 | [HttpPost("addUserRoles")] 53 | public async Task AddUserRole([FromBody] AddUserModel addUser) 54 | { 55 | var result = await _roleService.AddUserRoleAsync(addUser.UserEmail, addUser.Roles); 56 | 57 | if (!result) 58 | { 59 | return BadRequest(); 60 | } 61 | 62 | return StatusCode((int)HttpStatusCode.Created, result); 63 | } 64 | 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /idenitywebapiauthenitcation/Controllers/UserController.cs: -------------------------------------------------------------------------------- 1 | using idenitywebapiauthenitcation.Model; 2 | using idenitywebapiauthenitcation.Services; 3 | using Microsoft.AspNetCore.Authorization; 4 | using Microsoft.AspNetCore.Http; 5 | using Microsoft.AspNetCore.Identity; 6 | using Microsoft.AspNetCore.Mvc; 7 | 8 | namespace idenitywebapiauthenitcation.Controllers 9 | { 10 | [Authorize] 11 | [Route("api/[controller]")] 12 | [ApiController] 13 | public class UserController : ControllerBase 14 | { 15 | private readonly SignInManager _signInManager; 16 | private readonly IUserService _userService; 17 | 18 | public UserController(SignInManager signInManager, IUserService userService) 19 | { 20 | _signInManager = signInManager; 21 | _userService = userService; 22 | } 23 | 24 | [Authorize(Roles = "admin")] 25 | [HttpGet] 26 | public async Task Get() 27 | { 28 | var userList = await _userService.GetAllUsers(); 29 | return Ok(userList); 30 | } 31 | 32 | [Authorize(Roles = "admin")] 33 | [HttpGet("{emailId}")] 34 | public async Task Get(string emailId) 35 | { 36 | var userList = await _userService.GetUserByEmail(emailId); 37 | return Ok(userList); 38 | } 39 | 40 | [Authorize(Roles = "admin")] 41 | [HttpPut("{emailId}")] 42 | public async Task UpdateUser(string emailId, [FromBody] UserModel userModel) 43 | { 44 | var result = await _userService.UpdateUser(emailId, userModel); 45 | if (!result) 46 | { 47 | return BadRequest(); 48 | } 49 | return NoContent(); 50 | } 51 | 52 | [Authorize(Roles = "admin")] 53 | [HttpDelete("{emailId}")] 54 | public async Task Delete(string emailId) 55 | { 56 | var result = await _userService.DeleteUserByEmail(emailId); 57 | if (!result) 58 | { 59 | return BadRequest(); 60 | } 61 | return NoContent(); 62 | } 63 | [Authorize] 64 | [HttpPost("logout")] 65 | public async Task Logout([FromBody] object empty) 66 | { 67 | //{} 68 | if (empty is not null) 69 | { 70 | await _signInManager.SignOutAsync(); 71 | } 72 | return Ok(); 73 | } 74 | 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /idenitywebapiauthenitcation/Data/IdentityDbContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Identity.EntityFrameworkCore; 2 | using Microsoft.AspNetCore.Identity; 3 | using Microsoft.EntityFrameworkCore; 4 | using idenitywebapiauthenitcation.Entity; 5 | 6 | namespace idenitywebapiauthenitcation.Data 7 | { 8 | public class IdentityDbContext : IdentityDbContext 9 | { 10 | public IdentityDbContext(DbContextOptions dbContextOptions) 11 | : base(dbContextOptions) 12 | { 13 | 14 | } 15 | 16 | public DbSet Blogs { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /idenitywebapiauthenitcation/Entity/Blog.cs: -------------------------------------------------------------------------------- 1 | namespace idenitywebapiauthenitcation.Entity 2 | { 3 | public class Blog 4 | { 5 | public int Id { get; set; } 6 | public string Name { get; set; } 7 | public string Description { get; set; } 8 | 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /idenitywebapiauthenitcation/Migrations/20240324090534_apiidenity.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | using idenitywebapiauthenitcation.Data; 9 | 10 | #nullable disable 11 | 12 | namespace idenitywebapiauthenitcation.Migrations 13 | { 14 | [DbContext(typeof(IdentityDbContext))] 15 | [Migration("20240324090534_apiidenity")] 16 | partial class apiidenity 17 | { 18 | /// 19 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 20 | { 21 | #pragma warning disable 612, 618 22 | modelBuilder 23 | .HasAnnotation("ProductVersion", "8.0.3") 24 | .HasAnnotation("Relational:MaxIdentifierLength", 128); 25 | 26 | SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); 27 | 28 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => 29 | { 30 | b.Property("Id") 31 | .HasColumnType("nvarchar(450)"); 32 | 33 | b.Property("ConcurrencyStamp") 34 | .IsConcurrencyToken() 35 | .HasColumnType("nvarchar(max)"); 36 | 37 | b.Property("Name") 38 | .HasMaxLength(256) 39 | .HasColumnType("nvarchar(256)"); 40 | 41 | b.Property("NormalizedName") 42 | .HasMaxLength(256) 43 | .HasColumnType("nvarchar(256)"); 44 | 45 | b.HasKey("Id"); 46 | 47 | b.HasIndex("NormalizedName") 48 | .IsUnique() 49 | .HasDatabaseName("RoleNameIndex") 50 | .HasFilter("[NormalizedName] IS NOT NULL"); 51 | 52 | b.ToTable("AspNetRoles", (string)null); 53 | }); 54 | 55 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 56 | { 57 | b.Property("Id") 58 | .ValueGeneratedOnAdd() 59 | .HasColumnType("int"); 60 | 61 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); 62 | 63 | b.Property("ClaimType") 64 | .HasColumnType("nvarchar(max)"); 65 | 66 | b.Property("ClaimValue") 67 | .HasColumnType("nvarchar(max)"); 68 | 69 | b.Property("RoleId") 70 | .IsRequired() 71 | .HasColumnType("nvarchar(450)"); 72 | 73 | b.HasKey("Id"); 74 | 75 | b.HasIndex("RoleId"); 76 | 77 | b.ToTable("AspNetRoleClaims", (string)null); 78 | }); 79 | 80 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => 81 | { 82 | b.Property("Id") 83 | .HasColumnType("nvarchar(450)"); 84 | 85 | b.Property("AccessFailedCount") 86 | .HasColumnType("int"); 87 | 88 | b.Property("ConcurrencyStamp") 89 | .IsConcurrencyToken() 90 | .HasColumnType("nvarchar(max)"); 91 | 92 | b.Property("Email") 93 | .HasMaxLength(256) 94 | .HasColumnType("nvarchar(256)"); 95 | 96 | b.Property("EmailConfirmed") 97 | .HasColumnType("bit"); 98 | 99 | b.Property("LockoutEnabled") 100 | .HasColumnType("bit"); 101 | 102 | b.Property("LockoutEnd") 103 | .HasColumnType("datetimeoffset"); 104 | 105 | b.Property("NormalizedEmail") 106 | .HasMaxLength(256) 107 | .HasColumnType("nvarchar(256)"); 108 | 109 | b.Property("NormalizedUserName") 110 | .HasMaxLength(256) 111 | .HasColumnType("nvarchar(256)"); 112 | 113 | b.Property("PasswordHash") 114 | .HasColumnType("nvarchar(max)"); 115 | 116 | b.Property("PhoneNumber") 117 | .HasColumnType("nvarchar(max)"); 118 | 119 | b.Property("PhoneNumberConfirmed") 120 | .HasColumnType("bit"); 121 | 122 | b.Property("SecurityStamp") 123 | .HasColumnType("nvarchar(max)"); 124 | 125 | b.Property("TwoFactorEnabled") 126 | .HasColumnType("bit"); 127 | 128 | b.Property("UserName") 129 | .HasMaxLength(256) 130 | .HasColumnType("nvarchar(256)"); 131 | 132 | b.HasKey("Id"); 133 | 134 | b.HasIndex("NormalizedEmail") 135 | .HasDatabaseName("EmailIndex"); 136 | 137 | b.HasIndex("NormalizedUserName") 138 | .IsUnique() 139 | .HasDatabaseName("UserNameIndex") 140 | .HasFilter("[NormalizedUserName] IS NOT NULL"); 141 | 142 | b.ToTable("AspNetUsers", (string)null); 143 | }); 144 | 145 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 146 | { 147 | b.Property("Id") 148 | .ValueGeneratedOnAdd() 149 | .HasColumnType("int"); 150 | 151 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); 152 | 153 | b.Property("ClaimType") 154 | .HasColumnType("nvarchar(max)"); 155 | 156 | b.Property("ClaimValue") 157 | .HasColumnType("nvarchar(max)"); 158 | 159 | b.Property("UserId") 160 | .IsRequired() 161 | .HasColumnType("nvarchar(450)"); 162 | 163 | b.HasKey("Id"); 164 | 165 | b.HasIndex("UserId"); 166 | 167 | b.ToTable("AspNetUserClaims", (string)null); 168 | }); 169 | 170 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 171 | { 172 | b.Property("LoginProvider") 173 | .HasColumnType("nvarchar(450)"); 174 | 175 | b.Property("ProviderKey") 176 | .HasColumnType("nvarchar(450)"); 177 | 178 | b.Property("ProviderDisplayName") 179 | .HasColumnType("nvarchar(max)"); 180 | 181 | b.Property("UserId") 182 | .IsRequired() 183 | .HasColumnType("nvarchar(450)"); 184 | 185 | b.HasKey("LoginProvider", "ProviderKey"); 186 | 187 | b.HasIndex("UserId"); 188 | 189 | b.ToTable("AspNetUserLogins", (string)null); 190 | }); 191 | 192 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 193 | { 194 | b.Property("UserId") 195 | .HasColumnType("nvarchar(450)"); 196 | 197 | b.Property("RoleId") 198 | .HasColumnType("nvarchar(450)"); 199 | 200 | b.HasKey("UserId", "RoleId"); 201 | 202 | b.HasIndex("RoleId"); 203 | 204 | b.ToTable("AspNetUserRoles", (string)null); 205 | }); 206 | 207 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 208 | { 209 | b.Property("UserId") 210 | .HasColumnType("nvarchar(450)"); 211 | 212 | b.Property("LoginProvider") 213 | .HasColumnType("nvarchar(450)"); 214 | 215 | b.Property("Name") 216 | .HasColumnType("nvarchar(450)"); 217 | 218 | b.Property("Value") 219 | .HasColumnType("nvarchar(max)"); 220 | 221 | b.HasKey("UserId", "LoginProvider", "Name"); 222 | 223 | b.ToTable("AspNetUserTokens", (string)null); 224 | }); 225 | 226 | modelBuilder.Entity("idenitywebapiauthenitcation.Entity.Blog", b => 227 | { 228 | b.Property("Id") 229 | .ValueGeneratedOnAdd() 230 | .HasColumnType("int"); 231 | 232 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); 233 | 234 | b.Property("Description") 235 | .IsRequired() 236 | .HasColumnType("nvarchar(max)"); 237 | 238 | b.Property("Name") 239 | .IsRequired() 240 | .HasColumnType("nvarchar(max)"); 241 | 242 | b.HasKey("Id"); 243 | 244 | b.ToTable("Blogs"); 245 | }); 246 | 247 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 248 | { 249 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) 250 | .WithMany() 251 | .HasForeignKey("RoleId") 252 | .OnDelete(DeleteBehavior.Cascade) 253 | .IsRequired(); 254 | }); 255 | 256 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 257 | { 258 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) 259 | .WithMany() 260 | .HasForeignKey("UserId") 261 | .OnDelete(DeleteBehavior.Cascade) 262 | .IsRequired(); 263 | }); 264 | 265 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 266 | { 267 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) 268 | .WithMany() 269 | .HasForeignKey("UserId") 270 | .OnDelete(DeleteBehavior.Cascade) 271 | .IsRequired(); 272 | }); 273 | 274 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 275 | { 276 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) 277 | .WithMany() 278 | .HasForeignKey("RoleId") 279 | .OnDelete(DeleteBehavior.Cascade) 280 | .IsRequired(); 281 | 282 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) 283 | .WithMany() 284 | .HasForeignKey("UserId") 285 | .OnDelete(DeleteBehavior.Cascade) 286 | .IsRequired(); 287 | }); 288 | 289 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 290 | { 291 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) 292 | .WithMany() 293 | .HasForeignKey("UserId") 294 | .OnDelete(DeleteBehavior.Cascade) 295 | .IsRequired(); 296 | }); 297 | #pragma warning restore 612, 618 298 | } 299 | } 300 | } 301 | -------------------------------------------------------------------------------- /idenitywebapiauthenitcation/Migrations/20240324090534_apiidenity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Migrations; 3 | 4 | #nullable disable 5 | 6 | namespace idenitywebapiauthenitcation.Migrations 7 | { 8 | /// 9 | public partial class apiidenity : Migration 10 | { 11 | /// 12 | protected override void Up(MigrationBuilder migrationBuilder) 13 | { 14 | migrationBuilder.CreateTable( 15 | name: "AspNetRoles", 16 | columns: table => new 17 | { 18 | Id = table.Column(type: "nvarchar(450)", nullable: false), 19 | Name = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), 20 | NormalizedName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), 21 | ConcurrencyStamp = table.Column(type: "nvarchar(max)", nullable: true) 22 | }, 23 | constraints: table => 24 | { 25 | table.PrimaryKey("PK_AspNetRoles", x => x.Id); 26 | }); 27 | 28 | migrationBuilder.CreateTable( 29 | name: "AspNetUsers", 30 | columns: table => new 31 | { 32 | Id = table.Column(type: "nvarchar(450)", nullable: false), 33 | UserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), 34 | NormalizedUserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), 35 | Email = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), 36 | NormalizedEmail = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), 37 | EmailConfirmed = table.Column(type: "bit", nullable: false), 38 | PasswordHash = table.Column(type: "nvarchar(max)", nullable: true), 39 | SecurityStamp = table.Column(type: "nvarchar(max)", nullable: true), 40 | ConcurrencyStamp = table.Column(type: "nvarchar(max)", nullable: true), 41 | PhoneNumber = table.Column(type: "nvarchar(max)", nullable: true), 42 | PhoneNumberConfirmed = table.Column(type: "bit", nullable: false), 43 | TwoFactorEnabled = table.Column(type: "bit", nullable: false), 44 | LockoutEnd = table.Column(type: "datetimeoffset", nullable: true), 45 | LockoutEnabled = table.Column(type: "bit", nullable: false), 46 | AccessFailedCount = table.Column(type: "int", nullable: false) 47 | }, 48 | constraints: table => 49 | { 50 | table.PrimaryKey("PK_AspNetUsers", x => x.Id); 51 | }); 52 | 53 | migrationBuilder.CreateTable( 54 | name: "Blogs", 55 | columns: table => new 56 | { 57 | Id = table.Column(type: "int", nullable: false) 58 | .Annotation("SqlServer:Identity", "1, 1"), 59 | Name = table.Column(type: "nvarchar(max)", nullable: false), 60 | Description = table.Column(type: "nvarchar(max)", nullable: false) 61 | }, 62 | constraints: table => 63 | { 64 | table.PrimaryKey("PK_Blogs", x => x.Id); 65 | }); 66 | 67 | migrationBuilder.CreateTable( 68 | name: "AspNetRoleClaims", 69 | columns: table => new 70 | { 71 | Id = table.Column(type: "int", nullable: false) 72 | .Annotation("SqlServer:Identity", "1, 1"), 73 | RoleId = table.Column(type: "nvarchar(450)", nullable: false), 74 | ClaimType = table.Column(type: "nvarchar(max)", nullable: true), 75 | ClaimValue = table.Column(type: "nvarchar(max)", nullable: true) 76 | }, 77 | constraints: table => 78 | { 79 | table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id); 80 | table.ForeignKey( 81 | name: "FK_AspNetRoleClaims_AspNetRoles_RoleId", 82 | column: x => x.RoleId, 83 | principalTable: "AspNetRoles", 84 | principalColumn: "Id", 85 | onDelete: ReferentialAction.Cascade); 86 | }); 87 | 88 | migrationBuilder.CreateTable( 89 | name: "AspNetUserClaims", 90 | columns: table => new 91 | { 92 | Id = table.Column(type: "int", nullable: false) 93 | .Annotation("SqlServer:Identity", "1, 1"), 94 | UserId = table.Column(type: "nvarchar(450)", nullable: false), 95 | ClaimType = table.Column(type: "nvarchar(max)", nullable: true), 96 | ClaimValue = table.Column(type: "nvarchar(max)", nullable: true) 97 | }, 98 | constraints: table => 99 | { 100 | table.PrimaryKey("PK_AspNetUserClaims", x => x.Id); 101 | table.ForeignKey( 102 | name: "FK_AspNetUserClaims_AspNetUsers_UserId", 103 | column: x => x.UserId, 104 | principalTable: "AspNetUsers", 105 | principalColumn: "Id", 106 | onDelete: ReferentialAction.Cascade); 107 | }); 108 | 109 | migrationBuilder.CreateTable( 110 | name: "AspNetUserLogins", 111 | columns: table => new 112 | { 113 | LoginProvider = table.Column(type: "nvarchar(450)", nullable: false), 114 | ProviderKey = table.Column(type: "nvarchar(450)", nullable: false), 115 | ProviderDisplayName = table.Column(type: "nvarchar(max)", nullable: true), 116 | UserId = table.Column(type: "nvarchar(450)", nullable: false) 117 | }, 118 | constraints: table => 119 | { 120 | table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey }); 121 | table.ForeignKey( 122 | name: "FK_AspNetUserLogins_AspNetUsers_UserId", 123 | column: x => x.UserId, 124 | principalTable: "AspNetUsers", 125 | principalColumn: "Id", 126 | onDelete: ReferentialAction.Cascade); 127 | }); 128 | 129 | migrationBuilder.CreateTable( 130 | name: "AspNetUserRoles", 131 | columns: table => new 132 | { 133 | UserId = table.Column(type: "nvarchar(450)", nullable: false), 134 | RoleId = table.Column(type: "nvarchar(450)", nullable: false) 135 | }, 136 | constraints: table => 137 | { 138 | table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId }); 139 | table.ForeignKey( 140 | name: "FK_AspNetUserRoles_AspNetRoles_RoleId", 141 | column: x => x.RoleId, 142 | principalTable: "AspNetRoles", 143 | principalColumn: "Id", 144 | onDelete: ReferentialAction.Cascade); 145 | table.ForeignKey( 146 | name: "FK_AspNetUserRoles_AspNetUsers_UserId", 147 | column: x => x.UserId, 148 | principalTable: "AspNetUsers", 149 | principalColumn: "Id", 150 | onDelete: ReferentialAction.Cascade); 151 | }); 152 | 153 | migrationBuilder.CreateTable( 154 | name: "AspNetUserTokens", 155 | columns: table => new 156 | { 157 | UserId = table.Column(type: "nvarchar(450)", nullable: false), 158 | LoginProvider = table.Column(type: "nvarchar(450)", nullable: false), 159 | Name = table.Column(type: "nvarchar(450)", nullable: false), 160 | Value = table.Column(type: "nvarchar(max)", nullable: true) 161 | }, 162 | constraints: table => 163 | { 164 | table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); 165 | table.ForeignKey( 166 | name: "FK_AspNetUserTokens_AspNetUsers_UserId", 167 | column: x => x.UserId, 168 | principalTable: "AspNetUsers", 169 | principalColumn: "Id", 170 | onDelete: ReferentialAction.Cascade); 171 | }); 172 | 173 | migrationBuilder.CreateIndex( 174 | name: "IX_AspNetRoleClaims_RoleId", 175 | table: "AspNetRoleClaims", 176 | column: "RoleId"); 177 | 178 | migrationBuilder.CreateIndex( 179 | name: "RoleNameIndex", 180 | table: "AspNetRoles", 181 | column: "NormalizedName", 182 | unique: true, 183 | filter: "[NormalizedName] IS NOT NULL"); 184 | 185 | migrationBuilder.CreateIndex( 186 | name: "IX_AspNetUserClaims_UserId", 187 | table: "AspNetUserClaims", 188 | column: "UserId"); 189 | 190 | migrationBuilder.CreateIndex( 191 | name: "IX_AspNetUserLogins_UserId", 192 | table: "AspNetUserLogins", 193 | column: "UserId"); 194 | 195 | migrationBuilder.CreateIndex( 196 | name: "IX_AspNetUserRoles_RoleId", 197 | table: "AspNetUserRoles", 198 | column: "RoleId"); 199 | 200 | migrationBuilder.CreateIndex( 201 | name: "EmailIndex", 202 | table: "AspNetUsers", 203 | column: "NormalizedEmail"); 204 | 205 | migrationBuilder.CreateIndex( 206 | name: "UserNameIndex", 207 | table: "AspNetUsers", 208 | column: "NormalizedUserName", 209 | unique: true, 210 | filter: "[NormalizedUserName] IS NOT NULL"); 211 | } 212 | 213 | /// 214 | protected override void Down(MigrationBuilder migrationBuilder) 215 | { 216 | migrationBuilder.DropTable( 217 | name: "AspNetRoleClaims"); 218 | 219 | migrationBuilder.DropTable( 220 | name: "AspNetUserClaims"); 221 | 222 | migrationBuilder.DropTable( 223 | name: "AspNetUserLogins"); 224 | 225 | migrationBuilder.DropTable( 226 | name: "AspNetUserRoles"); 227 | 228 | migrationBuilder.DropTable( 229 | name: "AspNetUserTokens"); 230 | 231 | migrationBuilder.DropTable( 232 | name: "Blogs"); 233 | 234 | migrationBuilder.DropTable( 235 | name: "AspNetRoles"); 236 | 237 | migrationBuilder.DropTable( 238 | name: "AspNetUsers"); 239 | } 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /idenitywebapiauthenitcation/Migrations/IdentityDbContextModelSnapshot.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 7 | using idenitywebapiauthenitcation.Data; 8 | 9 | #nullable disable 10 | 11 | namespace idenitywebapiauthenitcation.Migrations 12 | { 13 | [DbContext(typeof(IdentityDbContext))] 14 | partial class IdentityDbContextModelSnapshot : ModelSnapshot 15 | { 16 | protected override void BuildModel(ModelBuilder modelBuilder) 17 | { 18 | #pragma warning disable 612, 618 19 | modelBuilder 20 | .HasAnnotation("ProductVersion", "8.0.3") 21 | .HasAnnotation("Relational:MaxIdentifierLength", 128); 22 | 23 | SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); 24 | 25 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => 26 | { 27 | b.Property("Id") 28 | .HasColumnType("nvarchar(450)"); 29 | 30 | b.Property("ConcurrencyStamp") 31 | .IsConcurrencyToken() 32 | .HasColumnType("nvarchar(max)"); 33 | 34 | b.Property("Name") 35 | .HasMaxLength(256) 36 | .HasColumnType("nvarchar(256)"); 37 | 38 | b.Property("NormalizedName") 39 | .HasMaxLength(256) 40 | .HasColumnType("nvarchar(256)"); 41 | 42 | b.HasKey("Id"); 43 | 44 | b.HasIndex("NormalizedName") 45 | .IsUnique() 46 | .HasDatabaseName("RoleNameIndex") 47 | .HasFilter("[NormalizedName] IS NOT NULL"); 48 | 49 | b.ToTable("AspNetRoles", (string)null); 50 | }); 51 | 52 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 53 | { 54 | b.Property("Id") 55 | .ValueGeneratedOnAdd() 56 | .HasColumnType("int"); 57 | 58 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); 59 | 60 | b.Property("ClaimType") 61 | .HasColumnType("nvarchar(max)"); 62 | 63 | b.Property("ClaimValue") 64 | .HasColumnType("nvarchar(max)"); 65 | 66 | b.Property("RoleId") 67 | .IsRequired() 68 | .HasColumnType("nvarchar(450)"); 69 | 70 | b.HasKey("Id"); 71 | 72 | b.HasIndex("RoleId"); 73 | 74 | b.ToTable("AspNetRoleClaims", (string)null); 75 | }); 76 | 77 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => 78 | { 79 | b.Property("Id") 80 | .HasColumnType("nvarchar(450)"); 81 | 82 | b.Property("AccessFailedCount") 83 | .HasColumnType("int"); 84 | 85 | b.Property("ConcurrencyStamp") 86 | .IsConcurrencyToken() 87 | .HasColumnType("nvarchar(max)"); 88 | 89 | b.Property("Email") 90 | .HasMaxLength(256) 91 | .HasColumnType("nvarchar(256)"); 92 | 93 | b.Property("EmailConfirmed") 94 | .HasColumnType("bit"); 95 | 96 | b.Property("LockoutEnabled") 97 | .HasColumnType("bit"); 98 | 99 | b.Property("LockoutEnd") 100 | .HasColumnType("datetimeoffset"); 101 | 102 | b.Property("NormalizedEmail") 103 | .HasMaxLength(256) 104 | .HasColumnType("nvarchar(256)"); 105 | 106 | b.Property("NormalizedUserName") 107 | .HasMaxLength(256) 108 | .HasColumnType("nvarchar(256)"); 109 | 110 | b.Property("PasswordHash") 111 | .HasColumnType("nvarchar(max)"); 112 | 113 | b.Property("PhoneNumber") 114 | .HasColumnType("nvarchar(max)"); 115 | 116 | b.Property("PhoneNumberConfirmed") 117 | .HasColumnType("bit"); 118 | 119 | b.Property("SecurityStamp") 120 | .HasColumnType("nvarchar(max)"); 121 | 122 | b.Property("TwoFactorEnabled") 123 | .HasColumnType("bit"); 124 | 125 | b.Property("UserName") 126 | .HasMaxLength(256) 127 | .HasColumnType("nvarchar(256)"); 128 | 129 | b.HasKey("Id"); 130 | 131 | b.HasIndex("NormalizedEmail") 132 | .HasDatabaseName("EmailIndex"); 133 | 134 | b.HasIndex("NormalizedUserName") 135 | .IsUnique() 136 | .HasDatabaseName("UserNameIndex") 137 | .HasFilter("[NormalizedUserName] IS NOT NULL"); 138 | 139 | b.ToTable("AspNetUsers", (string)null); 140 | }); 141 | 142 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 143 | { 144 | b.Property("Id") 145 | .ValueGeneratedOnAdd() 146 | .HasColumnType("int"); 147 | 148 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); 149 | 150 | b.Property("ClaimType") 151 | .HasColumnType("nvarchar(max)"); 152 | 153 | b.Property("ClaimValue") 154 | .HasColumnType("nvarchar(max)"); 155 | 156 | b.Property("UserId") 157 | .IsRequired() 158 | .HasColumnType("nvarchar(450)"); 159 | 160 | b.HasKey("Id"); 161 | 162 | b.HasIndex("UserId"); 163 | 164 | b.ToTable("AspNetUserClaims", (string)null); 165 | }); 166 | 167 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 168 | { 169 | b.Property("LoginProvider") 170 | .HasColumnType("nvarchar(450)"); 171 | 172 | b.Property("ProviderKey") 173 | .HasColumnType("nvarchar(450)"); 174 | 175 | b.Property("ProviderDisplayName") 176 | .HasColumnType("nvarchar(max)"); 177 | 178 | b.Property("UserId") 179 | .IsRequired() 180 | .HasColumnType("nvarchar(450)"); 181 | 182 | b.HasKey("LoginProvider", "ProviderKey"); 183 | 184 | b.HasIndex("UserId"); 185 | 186 | b.ToTable("AspNetUserLogins", (string)null); 187 | }); 188 | 189 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 190 | { 191 | b.Property("UserId") 192 | .HasColumnType("nvarchar(450)"); 193 | 194 | b.Property("RoleId") 195 | .HasColumnType("nvarchar(450)"); 196 | 197 | b.HasKey("UserId", "RoleId"); 198 | 199 | b.HasIndex("RoleId"); 200 | 201 | b.ToTable("AspNetUserRoles", (string)null); 202 | }); 203 | 204 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 205 | { 206 | b.Property("UserId") 207 | .HasColumnType("nvarchar(450)"); 208 | 209 | b.Property("LoginProvider") 210 | .HasColumnType("nvarchar(450)"); 211 | 212 | b.Property("Name") 213 | .HasColumnType("nvarchar(450)"); 214 | 215 | b.Property("Value") 216 | .HasColumnType("nvarchar(max)"); 217 | 218 | b.HasKey("UserId", "LoginProvider", "Name"); 219 | 220 | b.ToTable("AspNetUserTokens", (string)null); 221 | }); 222 | 223 | modelBuilder.Entity("idenitywebapiauthenitcation.Entity.Blog", b => 224 | { 225 | b.Property("Id") 226 | .ValueGeneratedOnAdd() 227 | .HasColumnType("int"); 228 | 229 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); 230 | 231 | b.Property("Description") 232 | .IsRequired() 233 | .HasColumnType("nvarchar(max)"); 234 | 235 | b.Property("Name") 236 | .IsRequired() 237 | .HasColumnType("nvarchar(max)"); 238 | 239 | b.HasKey("Id"); 240 | 241 | b.ToTable("Blogs"); 242 | }); 243 | 244 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 245 | { 246 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) 247 | .WithMany() 248 | .HasForeignKey("RoleId") 249 | .OnDelete(DeleteBehavior.Cascade) 250 | .IsRequired(); 251 | }); 252 | 253 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 254 | { 255 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) 256 | .WithMany() 257 | .HasForeignKey("UserId") 258 | .OnDelete(DeleteBehavior.Cascade) 259 | .IsRequired(); 260 | }); 261 | 262 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 263 | { 264 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) 265 | .WithMany() 266 | .HasForeignKey("UserId") 267 | .OnDelete(DeleteBehavior.Cascade) 268 | .IsRequired(); 269 | }); 270 | 271 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 272 | { 273 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) 274 | .WithMany() 275 | .HasForeignKey("RoleId") 276 | .OnDelete(DeleteBehavior.Cascade) 277 | .IsRequired(); 278 | 279 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) 280 | .WithMany() 281 | .HasForeignKey("UserId") 282 | .OnDelete(DeleteBehavior.Cascade) 283 | .IsRequired(); 284 | }); 285 | 286 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 287 | { 288 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) 289 | .WithMany() 290 | .HasForeignKey("UserId") 291 | .OnDelete(DeleteBehavior.Cascade) 292 | .IsRequired(); 293 | }); 294 | #pragma warning restore 612, 618 295 | } 296 | } 297 | } 298 | -------------------------------------------------------------------------------- /idenitywebapiauthenitcation/Model/AddUserModel.cs: -------------------------------------------------------------------------------- 1 | namespace idenitywebapiauthenitcation.Model 2 | { 3 | public class AddUserModel 4 | { 5 | public string UserEmail { get; set; } 6 | public string[] Roles { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /idenitywebapiauthenitcation/Model/RoleModel.cs: -------------------------------------------------------------------------------- 1 | namespace idenitywebapiauthenitcation.Model 2 | { 3 | public class RoleModel 4 | { 5 | public Guid Id { get; set; } 6 | public string Name { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /idenitywebapiauthenitcation/Model/UserModel.cs: -------------------------------------------------------------------------------- 1 | namespace idenitywebapiauthenitcation.Model 2 | { 3 | public class UserModel 4 | { 5 | public Guid Id { get; set; } 6 | public string UserName { get; set; } 7 | public string Email { get; set; } 8 | public string PhoneNumber { get; set; } 9 | 10 | public List Roles { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /idenitywebapiauthenitcation/Program.cs: -------------------------------------------------------------------------------- 1 | using idenitywebapiauthenitcation.Data; 2 | using idenitywebapiauthenitcation.Services; 3 | using Microsoft.AspNetCore.Identity; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.OpenApi.Models; 6 | using Swashbuckle.AspNetCore.Filters; 7 | 8 | var builder = WebApplication.CreateBuilder(args); 9 | 10 | // Add services to the container. 11 | 12 | builder.Services.AddDbContext(option => 13 | option.UseSqlServer(builder.Configuration.GetConnectionString("idenitycs"))); 14 | 15 | 16 | builder.Services.AddIdentityApiEndpoints(). 17 | AddRoles(). 18 | AddEntityFrameworkStores(); 19 | 20 | builder.Services.AddScoped(); 21 | builder.Services.AddScoped(); 22 | 23 | builder.Services.AddControllers(); 24 | // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle 25 | builder.Services.AddEndpointsApiExplorer(); 26 | builder.Services.AddSwaggerGen(option => 27 | { 28 | option.AddSecurityDefinition("oauth2", new Microsoft.OpenApi.Models.OpenApiSecurityScheme 29 | { 30 | In = Microsoft.OpenApi.Models.ParameterLocation.Header, 31 | Name = "Authorization", 32 | Type = SecuritySchemeType.ApiKey 33 | }); 34 | option.OperationFilter(); 35 | }); 36 | 37 | builder.Services.AddCors(option => option.AddPolicy("wasm", 38 | policy => policy.WithOrigins(builder.Configuration["BackendUrl"] ?? "", 39 | builder.Configuration["FrontendUrl"] ?? "") 40 | .AllowAnyMethod() 41 | .AllowAnyHeader() 42 | .AllowCredentials() 43 | )); 44 | 45 | 46 | var app = builder.Build(); 47 | 48 | app.MapIdentityApi(); 49 | 50 | app.UseCors("wasm"); 51 | // Configure the HTTP request pipeline. 52 | if (app.Environment.IsDevelopment()) 53 | { 54 | app.UseSwagger(); 55 | app.UseSwaggerUI(); 56 | } 57 | 58 | app.UseHttpsRedirection(); 59 | 60 | app.UseAuthorization(); 61 | 62 | app.MapControllers(); 63 | 64 | app.Run(); 65 | -------------------------------------------------------------------------------- /idenitywebapiauthenitcation/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:47335", 8 | "sslPort": 44360 9 | } 10 | }, 11 | "profiles": { 12 | "http": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "launchUrl": "swagger", 17 | "applicationUrl": "http://localhost:5242", 18 | "environmentVariables": { 19 | "ASPNETCORE_ENVIRONMENT": "Development" 20 | } 21 | }, 22 | "https": { 23 | "commandName": "Project", 24 | "dotnetRunMessages": true, 25 | "launchBrowser": true, 26 | "launchUrl": "swagger", 27 | "applicationUrl": "https://localhost:7239;http://localhost:5242", 28 | "environmentVariables": { 29 | "ASPNETCORE_ENVIRONMENT": "Development" 30 | } 31 | }, 32 | "IIS Express": { 33 | "commandName": "IISExpress", 34 | "launchBrowser": true, 35 | "launchUrl": "swagger", 36 | "environmentVariables": { 37 | "ASPNETCORE_ENVIRONMENT": "Development" 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /idenitywebapiauthenitcation/Services/IRoleService.cs: -------------------------------------------------------------------------------- 1 | using idenitywebapiauthenitcation.Model; 2 | 3 | namespace idenitywebapiauthenitcation.Services 4 | { 5 | public interface IRoleService 6 | { 7 | Task> GetRolesAsync(); 8 | 9 | Task> GetUserRolesAsync(string emailId); 10 | 11 | Task> AddRolesAsync(string[] roles); 12 | 13 | Task AddUserRoleAsync(string userEmail, string[] roles); 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /idenitywebapiauthenitcation/Services/IUserService.cs: -------------------------------------------------------------------------------- 1 | using idenitywebapiauthenitcation.Model; 2 | 3 | namespace idenitywebapiauthenitcation.Services 4 | { 5 | public interface IUserService 6 | { 7 | Task> GetAllUsers(); 8 | 9 | Task GetUserByEmail(string emailId); 10 | 11 | Task UpdateUser(string emailId, UserModel user); 12 | 13 | Task DeleteUserByEmail(string emailId); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /idenitywebapiauthenitcation/Services/RoleService.cs: -------------------------------------------------------------------------------- 1 | using idenitywebapiauthenitcation.Model; 2 | using Microsoft.AspNetCore.Identity; 3 | 4 | namespace idenitywebapiauthenitcation.Services 5 | { 6 | public class RoleService : IRoleService 7 | { 8 | private readonly RoleManager _roleManager; 9 | private readonly UserManager _userManager; 10 | 11 | public RoleService(RoleManager roleManager, 12 | UserManager userManager) 13 | { 14 | _roleManager = roleManager; 15 | _userManager = userManager; 16 | } 17 | public async Task> GetRolesAsync() 18 | { 19 | var roleList = _roleManager.Roles.Select(x => 20 | new RoleModel { Id = Guid.Parse(x.Id), Name = x.Name }).ToList(); 21 | return roleList; 22 | } 23 | 24 | public async Task> GetUserRolesAsync(string emailId) 25 | { 26 | var user = await _userManager.FindByEmailAsync(emailId); 27 | 28 | var userRoles = await _userManager.GetRolesAsync(user); 29 | return userRoles.ToList(); 30 | } 31 | public async Task> AddRolesAsync(string[] roles) 32 | { 33 | var rolesList = new List(); 34 | foreach (var role in roles) 35 | { 36 | if(!await _roleManager.RoleExistsAsync(role)) 37 | { 38 | await _roleManager.CreateAsync(new IdentityRole(role)); 39 | rolesList.Add(role); 40 | } 41 | } 42 | return rolesList; 43 | } 44 | 45 | public async Task AddUserRoleAsync(string userEmail, string[] roles) 46 | { 47 | var user = await _userManager.FindByEmailAsync(userEmail); 48 | 49 | var exitsRoles = await ExistsRolesAsync(roles); 50 | 51 | if(user != null && exitsRoles.Count == roles.Length) 52 | { 53 | var assginRoles = await _userManager.AddToRolesAsync(user, exitsRoles); 54 | return assginRoles.Succeeded; 55 | } 56 | 57 | return false; 58 | 59 | } 60 | 61 | private async Task> ExistsRolesAsync(string[] roles) 62 | { 63 | var rolesList = new List(); 64 | foreach (var role in roles) 65 | { 66 | var roleExist = await _roleManager.RoleExistsAsync(role); 67 | if (roleExist) 68 | { 69 | rolesList.Add(role); 70 | } 71 | } 72 | return rolesList; 73 | 74 | } 75 | 76 | 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /idenitywebapiauthenitcation/Services/UserService.cs: -------------------------------------------------------------------------------- 1 | using idenitywebapiauthenitcation.Model; 2 | using Microsoft.AspNetCore.Identity; 3 | 4 | namespace idenitywebapiauthenitcation.Services 5 | { 6 | public class UserService : IUserService 7 | { 8 | private readonly UserManager _userManager; 9 | private readonly IRoleService _roleService; 10 | 11 | public UserService(UserManager userManager, IRoleService roleService) 12 | { 13 | _userManager = userManager; 14 | _roleService = roleService; 15 | } 16 | 17 | public async Task> GetAllUsers() 18 | { 19 | var response = new List(); 20 | var users = _userManager.Users.ToList(); 21 | foreach (var x in users) 22 | { 23 | var userRoles = await _userManager.GetRolesAsync(x); 24 | var user = new UserModel 25 | { 26 | Id = Guid.Parse(x.Id), 27 | Email = x.Email, 28 | PhoneNumber = x.PhoneNumber, 29 | UserName = x.UserName, 30 | Roles = userRoles.ToList(), 31 | }; 32 | 33 | response.Add(user); 34 | } 35 | return response; 36 | } 37 | 38 | public async Task GetUserByEmail(string emailId) 39 | { 40 | var user = await _userManager.FindByEmailAsync(emailId); 41 | var userRoles = await _userManager.GetRolesAsync(user); 42 | var userModel = new UserModel 43 | { 44 | Id = Guid.Parse(user.Id), 45 | Email = user.Email, 46 | PhoneNumber = user.PhoneNumber, 47 | UserName = user.UserName, 48 | Roles = userRoles.ToList(), 49 | }; 50 | return userModel; 51 | 52 | } 53 | public async Task DeleteUserByEmail(string emailId) 54 | { 55 | 56 | var user = await _userManager.FindByEmailAsync(emailId); 57 | var result = await _userManager.DeleteAsync(user); 58 | return result.Succeeded; 59 | } 60 | 61 | 62 | 63 | public async Task UpdateUser(string emailId, UserModel user) 64 | { 65 | // 66 | // user role - admin,hr 67 | var userIdentity = await _userManager.FindByEmailAsync(emailId); 68 | if (userIdentity == null) 69 | { 70 | return false; 71 | } 72 | 73 | userIdentity.UserName = user.UserName; 74 | userIdentity.Email = user.Email; 75 | userIdentity.PhoneNumber = user.PhoneNumber; 76 | 77 | var updateReponse = await _userManager.UpdateAsync(userIdentity); 78 | if (updateReponse.Succeeded) 79 | { 80 | // admin,user 81 | var currentUserRole = await _userManager.GetRolesAsync(userIdentity); 82 | // user role - admin,hr 83 | var removeUserRole = currentUserRole.Except(user.Roles); 84 | // user 85 | var removeRoleResult = await _userManager.RemoveFromRolesAsync(userIdentity, removeUserRole); 86 | if (removeRoleResult.Succeeded) 87 | { 88 | // user role - admin,hr 89 | // current user - admin 90 | var uniqueRole = user.Roles.Except(currentUserRole); 91 | // hr 92 | var assginRoleResult = await _roleService.AddUserRoleAsync(userIdentity.Email, uniqueRole.ToArray()); 93 | return assginRoleResult; 94 | } 95 | } 96 | return false; 97 | 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /idenitywebapiauthenitcation/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /idenitywebapiauthenitcation/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*", 9 | "ConnectionStrings": { 10 | "idenitycs": "Data Source=.;Initial Catalog=idenityapidb;Integrated Security=True;TrustServerCertificate=True;Trusted_Connection=True;Connection Timeout=30;" 11 | }, 12 | "BackendUrl": "https://localhost:7239", 13 | "FrontendUrl": "https://localhost:7195" 14 | } 15 | -------------------------------------------------------------------------------- /idenitywebapiauthenitcation/idenitywebapiauthenitcation.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | all 13 | runtime; build; native; contentfiles; analyzers; buildtransitive 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /idenitywebapiauthenitcation/idenitywebapiauthenitcation.http: -------------------------------------------------------------------------------- 1 | @idenitywebapiauthenitcation_HostAddress = https://localhost:7239 2 | 3 | GET {{idenitywebapiauthenitcation_HostAddress}}/weatherforecast/ 4 | Accept: application/json 5 | 6 | ### 7 | 8 | GET {{idenitywebapiauthenitcation_HostAddress}}/api/user 9 | Authorization: Bearer CfDJ8BHWDgVmgGlCt9OD0TT-MJ1oYon2Tv_C51fBLmryZSs4AW9pgQc7u2dYl-VcNyTsXhtMD_IaoVac9wHH35rVqJEKL7ZhoB4Ibdqj3h3Vzc_Ruwky52z3tU2q-J_o2Hl827gVN-RdhLJdWvVRgjySGBT81CgtfxkOumVuQqdwxkLswhfHUbYEcD_HGx1PUe1qcG1yaGBraP4qlLNWeLQkA4MrMERWhgpmPbqZXCArhllqySMNGmG8xGZ21i-kyuHl28sZgNtK_SrFZu59tF_NIZ3LeF8TxU-klkygslXmUg6sNCtwQ4TOXF6fPYk8BgNP2uTMymWgBYaGCELHPzskkueXXNDXINA1I6EIG9T35Jh3UAjckyF_Xf3Y85hR9RAlxBPJmkUisM9ag4HKADfgC-qP9tdIffQoP9QwidWLZhsRcp48DvbozVPcpLhJedwY5YbhuRl45zEYhMkJVxE6moZv75OOHypNakUgjU8tSZFV8Zy4_3lGBrf_ii4082gxxjIC_er0W9ktRfL2BCxnDMEjmurN_Rb86cKbLQ-BYyfEhAtbr6RZXYoHL-01yyZzVZRWIWrJJep9KTSTmKQNiAuWfrbd-L-DvpGA7cWtpnlRXltXXHE0PKlMWd7bTYHLakjniGG2mSCR9WP4wQ8gP6ohmVVu88FzYM_vRprQdLuCDiIoyo700V2bQA1UEDMc9A 10 | ### 11 | -------------------------------------------------------------------------------- /idenitywebapiauthenitcation/libman.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0", 3 | "defaultProvider": "cdnjs", 4 | "libraries": [] 5 | } -------------------------------------------------------------------------------- /workload-install.ps1: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) Samsung Electronics. All rights reserved. 3 | # Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | # 5 | 6 | <# 7 | .SYNOPSIS 8 | Installs Tizen workload manifest. 9 | .DESCRIPTION 10 | Installs the WorkloadManifest.json and WorkloadManifest.targets files for Tizen to the dotnet sdk. 11 | .PARAMETER Version 12 | Use specific VERSION 13 | .PARAMETER DotnetInstallDir 14 | Dotnet SDK Location installed 15 | #> 16 | 17 | [cmdletbinding()] 18 | param( 19 | [Alias('v')][string]$Version="", 20 | [Alias('d')][string]$DotnetInstallDir="", 21 | [Alias('t')][string]$DotnetTargetVersionBand="", 22 | [Alias('u')][switch]$UpdateAllWorkloads 23 | ) 24 | 25 | Set-StrictMode -Version Latest 26 | $ErrorActionPreference = "Stop" 27 | $ProgressPreference = "SilentlyContinue" 28 | 29 | $ManifestBaseName = "Samsung.NET.Sdk.Tizen.Manifest" 30 | 31 | $LatestVersionMap = @{ 32 | "$ManifestBaseName-6.0.100" = "7.0.101"; 33 | "$ManifestBaseName-6.0.200" = "7.0.100-preview.13.6"; 34 | "$ManifestBaseName-6.0.300" = "8.0.133"; 35 | "$ManifestBaseName-6.0.400" = "8.0.140"; 36 | "$ManifestBaseName-7.0.100-preview.6" = "7.0.100-preview.6.14"; 37 | "$ManifestBaseName-7.0.100-preview.7" = "7.0.100-preview.7.20"; 38 | "$ManifestBaseName-7.0.100-rc.1" = "7.0.100-rc.1.22"; 39 | "$ManifestBaseName-7.0.100-rc.2" = "7.0.100-rc.2.24"; 40 | "$ManifestBaseName-7.0.100" = "7.0.103"; 41 | "$ManifestBaseName-7.0.200" = "7.0.105"; 42 | "$ManifestBaseName-7.0.300" = "7.0.120"; 43 | "$ManifestBaseName-7.0.400" = "8.0.141"; 44 | "$ManifestBaseName-8.0.100-alpha.1" = "7.0.104"; 45 | "$ManifestBaseName-8.0.100-preview.2" = "7.0.106"; 46 | "$ManifestBaseName-8.0.100-preview.3" = "7.0.107"; 47 | "$ManifestBaseName-8.0.100-preview.4" = "7.0.108"; 48 | "$ManifestBaseName-8.0.100-preview.5" = "7.0.110"; 49 | "$ManifestBaseName-8.0.100-preview.6" = "7.0.121"; 50 | "$ManifestBaseName-8.0.100-preview.7" = "7.0.122"; 51 | "$ManifestBaseName-8.0.100-rc.1" = "7.0.124"; 52 | "$ManifestBaseName-8.0.100-rc.2" = "7.0.125"; 53 | "$ManifestBaseName-8.0.100-rtm" = "7.0.127"; 54 | "$ManifestBaseName-8.0.100" = "8.0.144"; 55 | "$ManifestBaseName-8.0.200" = "8.0.145"; 56 | "$ManifestBaseName-9.0.100-alpha.1" = "8.0.134"; 57 | "$ManifestBaseName-9.0.100-preview.1" = "8.0.135"; 58 | "$ManifestBaseName-9.0.100-preview.2" = "8.0.137"; 59 | } 60 | 61 | function New-TemporaryDirectory { 62 | $parent = [System.IO.Path]::GetTempPath() 63 | $name = [System.IO.Path]::GetRandomFileName() 64 | New-Item -ItemType Directory -Path (Join-Path $parent $name) 65 | } 66 | 67 | function Ensure-Directory([string]$TestDir) { 68 | Try { 69 | New-Item -ItemType Directory -Path $TestDir -Force -ErrorAction stop | Out-Null 70 | [io.file]::OpenWrite($(Join-Path -Path $TestDir -ChildPath ".test-write-access")).Close() 71 | Remove-Item -Path $(Join-Path -Path $TestDir -ChildPath ".test-write-access") -Force 72 | } 73 | Catch [System.UnauthorizedAccessException] { 74 | Write-Error "No permission to install. Try run with administrator mode." 75 | } 76 | } 77 | 78 | function Get-LatestVersion([string]$Id) { 79 | $attempts=3 80 | $sleepInSeconds=3 81 | do 82 | { 83 | try 84 | { 85 | $Response = Invoke-WebRequest -Uri https://api.nuget.org/v3-flatcontainer/$Id/index.json -UseBasicParsing | ConvertFrom-Json 86 | return $Response.versions | Select-Object -Last 1 87 | } 88 | catch { 89 | Write-Host "Id: $Id" 90 | Write-Host "An exception was caught: $($_.Exception.Message)" 91 | } 92 | 93 | $attempts-- 94 | if ($attempts -gt 0) { Start-Sleep $sleepInSeconds } 95 | } while ($attempts -gt 0) 96 | 97 | if ($LatestVersionMap.ContainsKey($Id)) 98 | { 99 | Write-Host "Return cached latest version." 100 | return $LatestVersionMap.$Id 101 | } else { 102 | Write-Error "Wrong Id: $Id" 103 | } 104 | } 105 | 106 | function Get-Package([string]$Id, [string]$Version, [string]$Destination, [string]$FileExt = "nupkg") { 107 | $OutFileName = "$Id.$Version.$FileExt" 108 | $OutFilePath = Join-Path -Path $Destination -ChildPath $OutFileName 109 | 110 | if ($Id -match ".net[0-9]+$") { 111 | $Id = $Id -replace (".net[0-9]+", "") 112 | } 113 | 114 | Invoke-WebRequest -Uri "https://www.nuget.org/api/v2/package/$Id/$Version" -OutFile $OutFilePath 115 | 116 | return $OutFilePath 117 | } 118 | 119 | function Install-Pack([string]$Id, [string]$Version, [string]$Kind) { 120 | $TempZipFile = $(Get-Package -Id $Id -Version $Version -Destination $TempDir -FileExt "zip") 121 | $TempUnzipDir = Join-Path -Path $TempDir -ChildPath "unzipped\$Id" 122 | 123 | switch ($Kind) { 124 | "manifest" { 125 | Expand-Archive -Path $TempZipFile -DestinationPath $TempUnzipDir 126 | New-Item -Path $TizenManifestDir -ItemType "directory" -Force | Out-Null 127 | Copy-Item -Path "$TempUnzipDir\data\*" -Destination $TizenManifestDir -Force 128 | } 129 | {($_ -eq "sdk") -or ($_ -eq "framework")} { 130 | Expand-Archive -Path $TempZipFile -DestinationPath $TempUnzipDir 131 | if ( ($kind -eq "sdk") -and ($Id -match ".net[0-9]+$")) { 132 | $Id = $Id -replace (".net[0-9]+", "") 133 | } 134 | $TargetDirectory = $(Join-Path -Path $DotnetInstallDir -ChildPath "packs\$Id\$Version") 135 | New-Item -Path $TargetDirectory -ItemType "directory" -Force | Out-Null 136 | Copy-Item -Path "$TempUnzipDir/*" -Destination $TargetDirectory -Recurse -Force 137 | } 138 | "template" { 139 | $TargetFileName = "$Id.$Version.nupkg".ToLower() 140 | $TargetDirectory = $(Join-Path -Path $DotnetInstallDir -ChildPath "template-packs") 141 | New-Item -Path $TargetDirectory -ItemType "directory" -Force | Out-Null 142 | Copy-Item $TempZipFile -Destination $(Join-Path -Path $TargetDirectory -ChildPath "$TargetFileName") -Force 143 | } 144 | } 145 | } 146 | 147 | function Remove-Pack([string]$Id, [string]$Version, [string]$Kind) { 148 | switch ($Kind) { 149 | "manifest" { 150 | Remove-Item -Path $TizenManifestDir -Recurse -Force 151 | } 152 | {($_ -eq "sdk") -or ($_ -eq "framework")} { 153 | $TargetDirectory = $(Join-Path -Path $DotnetInstallDir -ChildPath "packs\$Id\$Version") 154 | Remove-Item -Path $TargetDirectory -Recurse -Force 155 | } 156 | "template" { 157 | $TargetFileName = "$Id.$Version.nupkg".ToLower(); 158 | Remove-Item -Path $(Join-Path -Path $DotnetInstallDir -ChildPath "template-packs\$TargetFileName") -Force 159 | } 160 | } 161 | } 162 | 163 | function Install-TizenWorkload([string]$DotnetVersion) 164 | { 165 | $VersionSplitSymbol = '.' 166 | $SplitVersion = $DotnetVersion.Split($VersionSplitSymbol) 167 | 168 | $CurrentDotnetVersion = [Version]"$($SplitVersion[0]).$($SplitVersion[1])" 169 | $DotnetVersionBand = $SplitVersion[0] + $VersionSplitSymbol + $SplitVersion[1] + $VersionSplitSymbol + $SplitVersion[2][0] + "00" 170 | $ManifestName = "$ManifestBaseName-$DotnetVersionBand" 171 | 172 | if ($DotnetTargetVersionBand -eq "" -or $UpdateAllWorkloads.IsPresent) { 173 | if ($CurrentDotnetVersion -ge "7.0") 174 | { 175 | $IsPreviewVersion = $DotnetVersion.Contains("-preview") -or $DotnetVersion.Contains("-rc") -or $DotnetVersion.Contains("-alpha") 176 | if ($IsPreviewVersion -and ($SplitVersion.Count -ge 4)) { 177 | $DotnetTargetVersionBand = $DotnetVersionBand + $SplitVersion[2].SubString(3) + $VersionSplitSymbol + $($SplitVersion[3]) 178 | $ManifestName = "$ManifestBaseName-$DotnetTargetVersionBand" 179 | } 180 | elseif ($DotnetVersion.Contains("-rtm") -and ($SplitVersion.Count -ge 3)) { 181 | $DotnetTargetVersionBand = $DotnetVersionBand + $SplitVersion[2].SubString(3) 182 | $ManifestName = "$ManifestBaseName-$DotnetTargetVersionBand" 183 | } 184 | else { 185 | $DotnetTargetVersionBand = $DotnetVersionBand 186 | } 187 | } 188 | else { 189 | $DotnetTargetVersionBand = $DotnetVersionBand 190 | } 191 | } 192 | 193 | # Check latest version of manifest. 194 | if ($Version -eq "" -or $UpdateAllWorkloads.IsPresent) { 195 | $Version = Get-LatestVersion -Id $ManifestName 196 | } 197 | 198 | # Check workload manifest directory. 199 | $ManifestDir = Join-Path -Path $DotnetInstallDir -ChildPath "sdk-manifests" | Join-Path -ChildPath $DotnetTargetVersionBand 200 | $TizenManifestDir = Join-Path -Path $ManifestDir -ChildPath "samsung.net.sdk.tizen" 201 | $TizenManifestFile = Join-Path -Path $TizenManifestDir -ChildPath "WorkloadManifest.json" 202 | 203 | # Check and remove already installed old version. 204 | if (Test-Path $TizenManifestFile) { 205 | $ManifestJson = $(Get-Content $TizenManifestFile | ConvertFrom-Json) 206 | $OldVersion = $ManifestJson.version 207 | if ($OldVersion -eq $Version) { 208 | $DotnetWorkloadList = Invoke-Expression "& '$DotnetCommand' workload list | Select-String -Pattern '^tizen'" 209 | if ($DotnetWorkloadList) 210 | { 211 | Write-Host "Tizen Workload $Version version is already installed." 212 | Continue 213 | } 214 | } 215 | 216 | Ensure-Directory $ManifestDir 217 | Write-Host "Removing $ManifestName/$OldVersion from $ManifestDir..." 218 | Remove-Pack -Id $ManifestName -Version $OldVersion -Kind "manifest" 219 | $ManifestJson.packs.PSObject.Properties | ForEach-Object { 220 | Write-Host "Removing $($_.Name)/$($_.Value.version)..." 221 | Remove-Pack -Id $_.Name -Version $_.Value.version -Kind $_.Value.kind 222 | } 223 | } 224 | 225 | Ensure-Directory $ManifestDir 226 | $TempDir = $(New-TemporaryDirectory) 227 | 228 | # Install workload manifest. 229 | Write-Host "Installing $ManifestName/$Version to $ManifestDir..." 230 | Install-Pack -Id $ManifestName -Version $Version -Kind "manifest" 231 | 232 | # Download and install workload packs. 233 | $NewManifestJson = $(Get-Content $TizenManifestFile | ConvertFrom-Json) 234 | $NewManifestJson.packs.PSObject.Properties | ForEach-Object { 235 | Write-Host "Installing $($_.Name)/$($_.Value.version)..." 236 | Install-Pack -Id $_.Name -Version $_.Value.version -Kind $_.Value.kind 237 | } 238 | 239 | # Add tizen to the installed workload metadata. 240 | # Featured version band for metadata does NOT include any preview specifier. 241 | # https://github.com/dotnet/sdk/blob/main/documentation/general/workloads/user-local-workloads.md 242 | New-Item -Path $(Join-Path -Path $DotnetInstallDir -ChildPath "metadata\workloads\$DotnetVersionBand\InstalledWorkloads\tizen") -Force | Out-Null 243 | if (Test-Path $(Join-Path -Path $DotnetInstallDir -ChildPath "metadata\workloads\$DotnetVersionBand\InstallerType\msi")) { 244 | New-Item -Path "HKLM:\SOFTWARE\Microsoft\dotnet\InstalledWorkloads\Standalone\x64\$DotnetTargetVersionBand\tizen" -Force | Out-Null 245 | } 246 | 247 | # Clean up 248 | Remove-Item -Path $TempDir -Force -Recurse 249 | 250 | Write-Host "Done installing Tizen workload $Version" 251 | } 252 | 253 | # Check dotnet install directory. 254 | if ($DotnetInstallDir -eq "") { 255 | if ($Env:DOTNET_ROOT -And $(Test-Path "$Env:DOTNET_ROOT")) { 256 | $DotnetInstallDir = $Env:DOTNET_ROOT 257 | } else { 258 | $DotnetInstallDir = Join-Path -Path $Env:Programfiles -ChildPath "dotnet" 259 | } 260 | } 261 | if (-Not $(Test-Path "$DotnetInstallDir")) { 262 | Write-Error "No installed dotnet '$DotnetInstallDir'." 263 | } 264 | 265 | # Check installed dotnet version 266 | $DotnetCommand = "$DotnetInstallDir\dotnet" 267 | if (Get-Command $DotnetCommand -ErrorAction SilentlyContinue) 268 | { 269 | if ($UpdateAllWorkloads.IsPresent) 270 | { 271 | $InstalledDotnetSdks = Invoke-Expression "& '$DotnetCommand' --list-sdks | Select-String -Pattern '^6|^7'" | ForEach-Object {$_ -replace (" \[.*","")} 272 | } 273 | else 274 | { 275 | $InstalledDotnetSdks = Invoke-Expression "& '$DotnetCommand' --version" 276 | } 277 | } 278 | else 279 | { 280 | Write-Error "'$DotnetCommand' occurs an error." 281 | } 282 | 283 | if (-Not $InstalledDotnetSdks) 284 | { 285 | Write-Host "`n.NET SDK version 6 or later is required to install Tizen Workload." 286 | } 287 | else 288 | { 289 | foreach ($DotnetSdk in $InstalledDotnetSdks) 290 | { 291 | try { 292 | Write-Host "`nCheck Tizen Workload for sdk $DotnetSdk" 293 | Install-TizenWorkload -DotnetVersion $DotnetSdk 294 | } 295 | catch { 296 | Write-Host "Failed to install Tizen Workload for sdk $DotnetSdk" 297 | Write-Host "$_" 298 | Continue 299 | } 300 | } 301 | } 302 | 303 | Write-Host "`nDone" 304 | --------------------------------------------------------------------------------