我有一个SPA应用程序,其中包含一些受OpenID身份验证保护的WebAPI方法。用户首先登录SPA应用程序,然后在该应用程序中执行一些工作,然后需要通过向身份提供者重新进行身份验证来退出此工作。
SPA应用程序使用oidc-client-js。为了强制进行重新认证,我们在提示符下输入了值'login'。然后,用户会收到一个新的访问令牌,该令牌可用于调用WebAPI方法以退出工作。
注销WebAPI方法必须确保以首先登录到应用程序的身份注销工作。当应用程序仍在使用带有会话cookie的WsFed时(我们现在将其更改为OpenID),WebAPI能够断言传入身份与当前用户身份相同。但是,由于使用OpenID,我们不想使用会话cookie,因此WebAPI可能会同时要求登录访问令牌和签发访问令牌来断言两者都具有相同的身份。这似乎甚至没有任何意义。还能做到吗?签名WebAPI可能只需要声明签名身份就可以在工作上签名,而不管首先登录应用程序的用户的身份如何。
第二,用户必须单独签收以进行单独的工作。因此,当用户对资源A进行工作,通过与身份提供者重新认证来注销对资源A的工作并随后对资源B进行工作时,WebAPI需要确保对资源B的工作进行签名。使用为资源B获得的访问令牌,而不是先前为资源A获得的访问令牌。
在重新认证工作时,我们在重定向uri中指定资源Guid(这可能需要在ADFS的答复URL中指定通配符?在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);
}
}
}
非常感谢您的帮助