2

我有一个 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 时,signoff 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);                
        }
    }
}

非常感谢您的帮助

4

0 回答 0