У меня есть приложение SPA с некоторыми методами WebAPI, которые защищены аутентификацией OpenID. Пользователь сначала входит в приложение SPA, затем выполняет некоторую работу в приложении, а затем должен подписаться на эту работу путем повторной аутентификации у поставщика удостоверений.
Приложение SPA использует oidc-client-js. Для принудительной повторной аутентификации мы передаем параметр подсказки со значением 'login'. Затем пользователь получает новый токен доступа, который можно использовать для вызова метода WebAPI для завершения работы.
Метод подписи WebAPI должен гарантировать, что работа будет завершена с тем же идентификатором, который вошел в приложение в первую очередь. Когда приложение все еще использовало WsFed с сессионными cookie-файлами (теперь мы меняем его на OpenID), WebAPI смог утверждать, что входящий идентификатор совпадает с текущим идентификатором пользователя. Но, поскольку с OpenID мы не хотим использовать сеансовые куки, возможно, WebAPI мог бы запросить как токен доступа для входа в систему, так и токен доступа для выхода, чтобы утверждать, что оба имеют одинаковую идентичность. Это даже не имеет смысла. Можно ли это сделать? Возможно, для подписи WebAPI нужно только утверждать, что удостоверение подписи имеет разрешение на завершение работы, независимо от личности пользователя, который вошел в приложение в первую очередь.
Во-вторых, пользователь должен отключиться отдельно для выполнения отдельных работ. Таким образом, когда пользователь выполняет работу с ресурсом A, подписывает работу с ресурсом A путем повторной аутентификации у поставщика удостоверений и впоследствии выполняет работу с ресурсом B, WebAPI должен гарантировать, что работа с ресурсом B будет завершена. с токеном доступа, полученным для ресурса B, а не с токеном доступа, полученным ранее для ресурса A.
При повторной проверке подлинности для подписи на работе мы указываем ресурс Guid в URI перенаправления (для этого может потребоваться указание подстановочного знака в URL-адресе ответа в ADFS? По-видимому, для него не требуется специальная настройка в IdentityServer3). Когда мы использовали WsFed, метод WebAPI выхода мог утверждать, что текущий URL-адрес запроса совпадает с URI перенаправления, содержащимся во входящем билете аутентификации. При использовании OpenId я не думаю, что токен доступа содержит URI перенаправления, для которого он был выпущен, верно? Так как же WebAPI-подписчик может утверждать, что был выдан токен доступа для текущего ресурса, который был отключен?
Ниже приведен код, основанный на том, как мы работали с WsFed, но я не уверен, что он будет работать с OpenID.
app.UseIdentityServerBearerTokenAuthentication(
new IdentityServerBearerTokenAuthenticationOptions
{
TokenProvider = new OAuthBearerAuthenticationProvider
{
OnValidateIdentity = context =>
{
var incomingIdentity = context.Ticket.Identity;
// is the redirect uri even in the authentication ticket?
incomingIdentity.AddClaim(new Claim(Business.ClaimTypes.RedirectUri,
context.Ticket.Properties.RedirectUri));
// without session cookies, do we even have a current user at this stage?
var user = context.OwinContext.Authentication.User;
if (user.Identity.IsAuthenticated)
{
incomingIdentity.AddClaim(new Claim(Business.ClaimTypes.RequestedBy,
user.Identity.Name));
}
return Task.CompletedTask;
}
}
});
и
public class SignoffAuthorizedAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var claimsPrincipal = (ClaimsPrincipal)filterContext.HttpContext.User;
var redirectUriClaim =
claimsPrincipal.Claims.FirstOrDefault(c => c.Type == Business.ClaimTypes.RedirectUri);
if (redirectUriClaim == null || filterContext.HttpContext.Request.Url !=
new Uri(redirectUriClaim.Value, UriKind.RelativeOrAbsolute))
{
filterContext.Result = new HttpStatusCodeResult(HttpStatusCode.Forbidden);
return;
}
var requestedByClaim =
claimsPrincipal.Claims.FirstOrDefault(c => c.Type == Business.ClaimTypes.RequestedBy);
if (requestedByClaim == null || claimsPrincipal.Identity.Name !=
requestedByClaim .Value)
{
filterContext.Result = new HttpStatusCodeResult(HttpStatusCode.Forbidden);
}
}
}
Большое спасибо за вашу помощь