Hello, friends,
I have a utility package (v13) which uses UmbracoAuthorizedApiController such that a logged-in back-office user could open a browser at a URL like https://mysite.com/umbraco/backoffice/MyPackage/GetSomething?param=true and the endpoint would return an HTML page constructed by some Razor files and info from the Umbraco install.
As a first step in updating this package to support v17, I wanted to test out the most basic webapi setup in a new (empty) Umbraco 17 site.
Following the documentation and some other packages on GitHub for examples, I have this simple demo:
Base Controller:
using Asp.Versioning;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Common.Attributes;
using Umbraco.Cms.Api.Common.Filters;
using Umbraco.Cms.Api.Management.Controllers;
using Umbraco.Cms.Web.Common.Authorization;
using UmbConstants = Umbraco.Cms.Core.Constants;
[ApiController]
[ApiVersion(SiteSpecificApiConfig.ApiVersion)]
[MapToApi(SiteSpecificApiConfig.ProjectAlias)]
[ApiExplorerSettings(GroupName = SiteSpecificApiConfig.ProjectDisplayName)]
[Authorize(Policy = AuthorizationPolicies.BackOfficeAccess)]
[JsonOptionsName(UmbConstants.JsonOptionsNames.BackOffice)]
public abstract class SiteSpecificApiControllerBase : ManagementApiControllerBase
{
}
Demo Controller:
using System;
using System.Net.Http;
using System.Text;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Security;
[SiteSpecificApiBackOfficeRoute("AuthorizedApi")]
public class AuthorizedApiController : SiteSpecificApiControllerBase
{
#region CTOR/DI
private readonly ILogger _logger;
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
public AuthorizedApiController(
ILogger<AuthorizedApiController> logger
, IBackOfficeSecurityAccessor backOfficeSecurityAccessor
)
{
_logger = logger;
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
}
#endregion
#region Tests & Examples
[HttpGet("Test")]
[ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
public bool Test()
{
return true;
}
[HttpGet("SayHello")]
[ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
public IActionResult SayHello()
{
IUser currentUser = _backOfficeSecurityAccessor.BackOfficeSecurity?.CurrentUser
?? throw new InvalidOperationException("No backoffice user found");
return Ok($"Hello, {currentUser.Name}");
}
[HttpGet("ExampleReturnHtml")]
[ProducesResponseType(typeof(ContentResult), StatusCodes.Status200OK)]
public IActionResult ExampleReturnHtml()
{
var returnSB = new StringBuilder();
returnSB.AppendLine("<h1>Hello! This is HTML</h1>");
returnSB.AppendLine($"<p>This is rendering on {DateTime.Today.ToShortDateString()}</p>");
return new ContentResult()
{
Content = new StringContent(
returnSB.ToString(),
Encoding.UTF8,
"text/html"
).ToString(),
StatusCode = 200,
ContentType = "text/html"
};
}
[HttpGet("ExampleReturnJson")]
[ProducesResponseType(typeof(JsonResult), StatusCodes.Status200OK)]
public IActionResult ExampleReturnJson()
{
var testData1 = new TimeSpan(1, 1, 1, 1);
// var testData2= new StatusMessage(true, "This is a test object so you can see JSON!");
return new JsonResult(testData1);
}
#endregion
}
When I go to http://mysite.local/umbraco/swagger/ I can select this controller in the drop-down, and it shows the various endpoints. If I use the âAuthorizeâ button to provide the back-office token, the âTry it outâ/âExecuteâ buttons work.
However, when I try to access these endpoints directly via a browser to the URL (ex: https://mysite.local/MySite/api/v1/AuthorizedApi/SayHello ), I get ERR_HTTP_RESPONSE_CODE_FAILURE 401 (Unauthorized), which makes sense I suppose, because the Swagger UI is not magically providing the authorization.
So, my question is - what do I need to add to my Controller code in order to make this work in a browser directly?