ASP.NET Core 6.0 - API Authorization
This article describes restricting access to the member's image API endpoint to the user or an authorized administrator. I will assume you have downloaded the ASP.NET Core 6.0 - Users With Comments Project.
Users With Comments Project and Article Series
The ASP.NET Core 6.0 - Users With Comments Project (UWCP) implements public member profiles and a moderated comment workflow from user submission to admin publication. I started with the ASP.NET Core 6.0 - Users With Device 2FA Project (UWD2FAP) which implements WebAuthn, also known as FIDO2, instead of authenticator apps. The latest version of the UWCP is published at Preview. KenHaggerty. Com. I encourage you to register and submit a comment. Details, screenshots, and related articles can be found at ASP.NET Core 6.0 - Users With Comments Project. The details page includes the version change log.
- ASP.NET Core 6.0 - Users With Comments
- ASP.NET Core 6.0 - API Implementation
- ASP.NET Core 6.0 - API Authorization
- ASP.NET Core 6.0 - Member Profile
- ASP.NET Core 6.0 - Profile Image Control
- ASP.NET Core 6.0 - Comments Workflow
- ASP.NET Core 6.0 - Filtered Comments
- ASP.NET Core 6.0 - Member Listings
- ASP.NET Core 6.0 - Lazy Load On Scroll
Visual Studio 2022 (VS 2022) is required to develop .NET 6 and ASP.NET Core 6.0 applications. .NET 6 and ASP.NET Core 6.0 are Long Term Support (LTS) releases and will be supported until November 08, 2024. .NET 5 is a Current release and will be supported until May 08, 2022. .NET 3.1 is a LTS release and will be supported until December 3, 2022. See .NET and .NET Core release lifecycle.
I wanted to encourage users to use a profile image. I had already implemented Croppie to crop and resize a file image before it is uploaded and stored as a Data URL. I developed a Profile Image Control which adds options to use a webcam snapshot, or a stock image stored on the server.
The Profile Image Control implements the ProfileImageControler and a partial view. The partial implements the JavaScript that calls the ProfileImageControler. The _ProfileImagePostPartial is displayed on the Manage Account > Picture and the Admin > AppUsers > Edit page.
<partial name="_ProfileImagePostPartial" />
Many API endpoints need restricted access. Some need access by the user and/or an authorized administrator. The UWCP implements Authorization policies. I added MemberProfile and Comments Claims.
The ProfileImageControler's Get method has an appUserId parameter with a default value = 0. If the appUserId is not set, the current user is granted read write access to their picture. The Admin > Edit page sets the appUserId to the edit user's id. The ProfileImageControler injects the AuthorizationService to authorize the MemberProfilesRead and MemberProfilesWrite policies for the admin user.
private readonly IUserService _userService; private readonly IAuthorizationService _authorizationService; private readonly IWebHostEnvironment _environment; public ProfileImageController( IUserService userService, IAuthorizationService authorizationService, IWebHostEnvironment environment) { _userService = userService; _environment = environment; _authorizationService = authorizationService; } [HttpGet] [Route("Get")] public async Task<JsonResult> GetAsync(int appUserId = 0) { if (!User.Identity?.IsAuthenticated ?? false) return new JsonResult(new { Status = "Failed", Errors = "Not Authenticated", Id = appUserId }); var currentAppUserId = int.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)); var useStaffStock = User != null && (User.Claims.Any(c => c.Type == AppClaimTypes.Comment && c.Value == AppClaimValues.Write) || User.Claims.Any(c => c.Type == AppClaimTypes.Super)); var canUpdate = false; if (appUserId == 0) { appUserId = currentAppUserId; canUpdate = true; } else { if (User == null || !(await _authorizationService.AuthorizeAsync(User, AuthorizationPolicies.MemberProfilesRead)).Succeeded) return new JsonResult(new { Status = "Failed", Errors = "Not Authorized", Id = currentAppUserId }); var userClaims = await _userService.GetAppUserClaimsAsync(appUserId).ConfigureAwait(false); useStaffStock = userClaims.Any(c => c.Type == AppClaimTypes.Comment && c.Value == AppClaimValues.Write) || userClaims.Any(c => c.Type == AppClaimTypes.Super); canUpdate = User != null && (await _authorizationService.AuthorizeAsync(User, AuthorizationPolicies.MemberProfilesWrite)).Succeeded; } var currentImageString = await _userService.GetMemberProfileImageStringAsync(appUserId).ConfigureAwait(false); if (string.IsNullOrEmpty(currentImageString)) currentImageString = AppSettings.AnonymousImage; else if (!currentImageString.StartsWith("data:image/")) { if (!System.IO.File.Exists(Path.Combine(_environment.WebRootPath, currentImageString[1..]))) currentImageString = AppSettings.NotFoundImage; } ProfileImageInputModel profileImageInputModel = new(); profileImageInputModel.Status = "Success"; profileImageInputModel.CanUpdate = canUpdate; profileImageInputModel.CurrentImageString = currentImageString; profileImageInputModel.ImageTagWidth = AppSettings.MemberImageWidth; profileImageInputModel.ShowRemove = currentImageString != AppSettings.AnonymousImage; profileImageInputModel.StockEnabled = AppSettings.ProfileImageStockEnabled; profileImageInputModel.CropEnabled = AppSettings.ProfileImageCropEnabled; profileImageInputModel.CaptureEnabled = AppSettings.ProfileImageCaptureEnabled; if (AppSettings.ProfileImageStockEnabled) { var directoryPath = Path.Combine(_environment.WebRootPath, AppSettings.ProfileImageStockFolder[1..]); if (useStaffStock) directoryPath = Path.Combine(_environment.WebRootPath, AppSettings.ProfileImageStaffFolder[1..]); // Add image file name and relative path to StockImages. string[] fileNamePaths = Directory.GetFiles(directoryPath); foreach (string fileNamePath in fileNamePaths) { var fileName = Path.GetFileName(fileNamePath); var relativePath = Path.Combine(useStaffStock ? AppSettings.ProfileImageStaffFolder : AppSettings.ProfileImageStockFolder, fileName); profileImageInputModel.StockImages.Add(fileName, relativePath); } } return new JsonResult(profileImageInputModel); }
Comments(0)