Благодаря предложению Кэмерон Тинкер я смог заставить это работать. Было несколько вещей, которые сбили меня с толку, поэтому я поделюсь ими здесь на случай, если кто-то испытает то же самое.
Если вы используете Okta, вы можете сделать все это через пакет промежуточного программного обеспечения Okta. Вы можете сделать это, просто используя библиотеку c# OpenID, но библиотека Okta.AspNetCore поможет вам в этом.
Сначала вы зарегистрируете промежуточное ПО в веб-приложении. Okta имеет множество примеров этого на своем сайте, и это довольно просто.
В вашем веб-приложении вы можете использовать это для получения токена (после того, как пользователь, конечно, прошел аутентификацию)
await context.HttpContext?.GetTokenAsync("id_token")
Отправьте это вместе с вашими вызовами API как часть заголовка, используя стандартный механизм:
"Authorization" : "Bearer [token]"
На стороне веб-API вы используете тот же пакет промежуточного программного обеспечения Okta.AspNetCore и можете затем украсить свои контроллеры с помощью [Авторизировать], чтобы обеспечить аутентификацию на них. Вот где я споткнулся. Если вы не используете сервер аутентификации по умолчанию в Okta и настроили пользовательский сервер для своего приложения, вам нужно указать c it и аудиторию в вашей конфигурации:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = OktaDefaults.ApiAuthenticationScheme;
options.DefaultChallengeScheme = OktaDefaults.ApiAuthenticationScheme;
options.DefaultSignInScheme = OktaDefaults.ApiAuthenticationScheme;
})
.AddOktaWebApi(new OktaWebApiOptions()
{
OktaDomain = oktaDomain,
AuthorizationServerId = authServerId,
Audience = clientId
});
services.AddAuthorization();
Я полностью забыл об аудитории - и с тем, как работает проверка токена, эта часть обязательна.
Оттуда промежуточное программное обеспечение позаботится о заполнении ClaimsPrincipal для вас, чтобы вы могли получить доступ к пользовательской информации через ClaimsPrincipal (HttpContext.User). Я закончил тем, что создал «CurrentUserService» и вытащил его в свою собственную библиотеку, чтобы я мог консолидировать там все свои обработчики аутентификации; тем самым позволяя моему веб-приложению и коду веб-API проверять разрешения и таким же образом получать информацию о текущем пользователе. Этот код здесь, если вы заинтересованы:
public interface ICurrentUserService
{
public ClaimsPrincipal GetCurrentUser();
public string GetCurrentUserDisplayName();
public string GetCurrentUserFullName();
public string GetCurrentUserId();
public DateTime? GetCurrentUserDob();
public string GetCurrentUserGender();
public AddressFromClaimsDTO GetCurentUserAddress();
public bool IsAuthenticated();
}
public class CurrentUserService : ICurrentUserService
{
private const string FULL_ADDRESS_CLAIM_TYPE = "address";
private readonly IHttpContextAccessor _context;
public CurrentUserService(IHttpContextAccessor context)
{
_context = context;
}
/// <summary>
/// Gets whether or not the current user context is authenticated.
/// </summary>
/// <returns></returns>
public bool IsAuthenticated()
{
return GetCurrentUser().Identity.IsAuthenticated;
}
/// <summary>
/// Gets the current user's address.
/// TODO: tie this into our address data model... but if addresses live in Okta what does that mean?
/// </summary>
/// <returns></returns>
public AddressFromClaimsDTO GetCurentUserAddress()
{
var addressClaim = GetClaim(FULL_ADDRESS_CLAIM_TYPE);
if (addressClaim != null)
{
//var parseValue = addressClaim.Value.ToString().Replace("{address:", "{\"address\":");
var address = JsonSerializer.Deserialize<AddressFromClaimsDTO>(addressClaim.Value.ToString());
return address;
}
else
{
return new AddressFromClaimsDTO();
}
}
public ClaimsPrincipal GetCurrentUser()
{
return _context.HttpContext.User;
}
public string GetCurrentUserDisplayName()
{
return GetCurrentUser().Identity.Name;
}
public string GetCurrentUserFullName()
{
throw new NotImplementedException();
}
public string GetCurrentUserId()
{
throw new NotImplementedException();
}
public DateTime? GetCurrentUserDob()
{
var claim = GetClaim("birthdate");
if (claim != null && !string.IsNullOrEmpty(claim.Value))
{
return DateTime.Parse(claim.Value);
}
else
{
return null;
}
}
public string GetCurrentUserGender()
{
return GetClaim("gender")?.Value.ToString();
}
public Claim GetClaim(string claimType)
{
return _context.HttpContext.User.FindFirst(x => x.Type == claimType);
}
}