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)