没有cookie或本地凭据的外部自身身份验证

本文关键字:外部 身份验证 cookie 没有 | 更新日期: 2023-09-27 18:10:11

我正在使用angular和webapi开发一个跨平台的web应用程序。问题是当angular应用运行在cordova容器中时。为了更好地使用设备上的其他应用程序,我需要使用SSO插件。这个插件是什么导致我的问题,因为它做了一些事情。它拦截了所有的http请求,并向报头添加了一个承载令牌,这是由第三方令牌提供商生成的,所以我无法解码它,并覆盖了我在报头中设置的任何承载令牌。它似乎还能阻止cookies。

所以当你不能发送你自己的本地凭据时,这就有点棘手了。

所以我从https://coding.abel.nu/2014/06/writing-an-owin-authentication-middleware/和http://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin.Security.OAuth/OAuthBearerAuthenticationHandler.cs

开始

所以我想我应该写自己的中间件来处理这个问题;我认为既然标准的oauth中间件可以在没有cookie的情况下工作,我应该不会很难让我的稍微不同的承载令牌中间件做到这一点。但事实并非如此……编写我自己的中间件…我能获得header,与外部令牌提供者验证,但我不能登录。

   protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()
        {
            try
            {
                // Find token in default location
                string requestToken = null;
                string authorization = Request.Headers.Get("Authorization");
                if (!string.IsNullOrEmpty(authorization))
                {
                    if (authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
                    {
                        requestToken = authorization.Substring("Bearer ".Length).Trim();
                    }
                }
.... Take the Request token call other Server, verify token...

    public override async Task<bool> InvokeAsync()
    {
         var ticket = await this.AuthenticateAsync();
         if(ticket != null)
         {
           this.Context.Authentication.SignIn(new AuthenticationProperties(), grantIdentity);
           return false;
         }
    }

所以最终SignIn不会导致错误或任何事情,但实际上并没有登录。一旦到达带有[authorization]属性的控制器操作,就会得到401。我没有启用任何外部cookie。很有可能我走错了路,或者我把它弄得太难了。

没有cookie或本地凭据的外部自身身份验证

你做得太辛苦了。

您应该更改默认的OAuthBearerAuthenticationProvider,而不是创建您自己的承载身份验证中间件。

下面是在查询字符串中发送令牌的示例。

//in Startup class
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
    Provider = new QueryStringOAuthBearerProvider(),
    //your settings
});
//implementation
public class QueryStringOAuthBearerProvider : OAuthBearerAuthenticationProvider
{
    private const string AccessTokenQueryKey = "access_token";
    public override Task RequestToken(OAuthRequestTokenContext context)
    {
        //check if token found in the default location - "Authorization: Bearer <token>" header
        if (string.IsNullOrEmpty(context.Token))
        {
            var token = context.Request.Query.Get(AccessTokenQueryKey);
            if (!string.IsNullOrEmpty(token))
            {
                context.Token = token;
            }
        }
        return Task.FromResult<object>(null);
    }
}

所以…我想早点回答这个问题,但是我能够在不覆盖authorize属性的情况下弄清楚它。我最后查看了OWIN安全代码的源代码。诀窍在于,您确实需要2个OWIN中间件组件。一种是我所说的服务器中间件(我从自己的源代码中偷来的)。服务器中间件响应挑战和/或如果您感到疯狂,则为您生成本地凭据。这个中间件也是一个被动中间件组件。除非有人要求,否则我不会着手生成本地凭据,因为这有点离题,但如果有人认为它会有帮助,我可以更新。

public class LowCalorieAuthenticationServerHandler : AuthenticationHandler<LowCalorieAuthenticationServerOptions>
{
    //Important this needs to be overriden, but just calls the base. 
    protected override Task<AuthenticationTicket> AuthenticateCoreAsync()
    {
        return Task.FromResult<AuthenticationTicket>(null);
    }
    /// <summary>The apply response challenge async.</summary>
    /// <returns>The <see cref="Task"/>.</returns>
    protected override async Task ApplyResponseChallengeAsync()
    {
        if (this.Response.StatusCode != 401)
        {
            Task.FromResult<object>(null);
            return;
        }
        var challenge = this.Helper.LookupChallenge(
            this.Options.AuthenticationType,
            this.Options.AuthenticationMode);
        if (challenge != null)
        {
            //OK in here you call the rediret to the 3rd party 
            //return a redirect to some endpoint
        }
        Task.FromResult<object>(null);
        return;
    }
}

注意重载AuthenticateCoreAsync()是如何返回的返回Task.FromResult(空);这是因为我们不希望这个中间件修改请求。applyresponsecchallengeasync将等待挑战并将您重定向到第三方登录。如果您想创建某种类型的本地令牌,您可以覆盖InvokeAsync方法

您需要的第二个中间件是令牌/外部凭据验证器。这将以某种方式对用户进行身份验证。对于内置于OWIN安全性中的本地承载令牌,它简单地对令牌进行反序列化,如果可以,并且令牌没有过期,它将对用户进行身份验证。因此,如果您希望使用第三方sso(例如google或其他任何东西)验证令牌,则可以在这里插入逻辑。在我的例子中,我不仅想调用第三方提供商来获取用户信息,还想检查他们的令牌是否对单点登录退出仍然有效,并防止多个会话。
public class LowCalorieAuthenticationHandler : AuthenticationHandler<LowCalorieAuthenticationOptions>
{
    //Going to give you the user for the request.. You Need to do 3 things here
    //1. Get the user claim from teh request somehow, either froma header, request string, or cookie what ever you want
    //2. validate the user with whatever user store or 3rd party SSO you want
    //3. Generate a AuthenticationTicket to send to on to the request, you can use that to see if the user is valid in any Identity collection you want.  
    protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()
    {


        //Good to throw in a point of override here.. but to keep it simple-ish
        string requestToken = null;
        string authorization = Request.Headers.Get("Authorization");
        //TOTAL FAKEOUT.. I am going to add a bearer token just so the simple sample works, but your client would have to provide this
        authorization = "Bearer  1234567869";
        //STEP 1 
        if (!string.IsNullOrEmpty(authorization) && authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
        {
            requestToken = authorization.Substring("Bearer ".Length).Trim();
            return await FakeExternalBearer(requestToken);
        }
        return null;
    }
    private async Task<AuthenticationTicket> FakeExternalBearer(string token)
    {
        var authenticationType = Options.AuthenticationType;
        //pretend to call extenal Resource server to get user //STEP 2
        //CallExternal(token)
        //Create the AuthTicket from the return.. I will fake it out
        var identity = new ClaimsIdentity(
                            authenticationType,
                            ClaimsIdentity.DefaultNameClaimType,
                            ClaimsIdentity.DefaultRoleClaimType);
        identity.AddClaim(new Claim(ClaimTypes.NameIdentifier,"user1", null, authenticationType));
        identity.AddClaim(new Claim(ClaimTypes.Name, "Jon",null, authenticationType));
        var properties = new AuthenticationProperties();
        properties.ExpiresUtc = DateTime.UtcNow.AddMinutes(1);
        properties.IssuedUtc = DateTime.UtcNow;
        var ticket =  new AuthenticationTicket(identity, properties);
        return ticket;
    }
}

这里我们重写了AuthenticateCoreAsync,但我们现在做了一些事情。这是你的用户身份验证。这是中间件的ACTIVE部分。注意,它需要返回一个有效的AuthenticationTicket。这将在每个请求上运行,所以要注意调用的内容和频率。所以我在这里有一个非常简单的例子https://github.com/jzoss/LowCalorieOwin如果有人对更多的细节感兴趣,请问。我可以添加更多。我确实把它弄得太难了,因为现在我明白了,它很简单,但是没有很好的例子来说明如何做到这一点。