【问题标题】:External Owin Authentication without cookies or Local credentials没有 cookie 或本地凭据的外部 Owin 身份验证
【发布时间】:2015-09-10 04:12:23
【问题描述】:

我正在使用 Angular 和 webapi 开发跨平台 Web 应用程序。问题是当角度应用程序在科尔多瓦容器中运行时。为了与设备上的其他应用程序配合使用,我需要使用 SSO 插件。这个插件是导致我出现问题的原因,因为它做了一些事情。它拦截所有http请求并向标头添加一个不记名令牌,该不记名令牌由第3方令牌提供程序生成,因此我无法对其进行解码,并覆盖我在标头中设置的任何不记名令牌。它似乎也阻止了饼干..

因此,当您无法向您发送自己的本地凭据时,它会变得有点棘手。

所以我从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 的情况下工作,我应该不会花太多时间让我稍微不同的不记名令牌中间件来做到这一点。但事实并非如此......编写我自己的中间件......所以我'能够获取标头,通过外部令牌提供程序进行验证,但我实际上无法登录。

   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;
         }
    }

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

【问题讨论】:

  • 我发现只覆盖授权属性更简单。我问了一个类似的问题,这个人给了我以下链接(BitOfTech.net)。如果你明白了,请发帖 (stackoverflow.com/questions/32099027/…)
  • @Mr.B - 嘿,看看我的答案。我终于能做到了。

标签: c# oauth asp.net-web-api owin bearer-token


【解决方案1】:

你做得太难了。

您应该更改默认的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);
    }
}

【讨论】:

    【解决方案2】:

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

    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(null); 这是因为我们不希望这个中间件修改请求。 ApplyResponseChallengeAsync 将等待挑战并将您重定向到第 3 方登录。如果您想创建某种本地令牌,您将覆盖 InvokeAsync 方法

    您需要的第二个中间件是令牌/外部凭据验证器。然后,这将以某种方式对用户进行身份验证。对于内置在 OWIN 安全性中的本地不记名令牌,它会简单地反序列化令牌,如果可以,并且令牌未过期,它会对用户进行身份验证。因此,如果您想使用第三部分 sso 验证令牌,例如 google 或其他任何东西,您可以在此处插入逻辑。在我的情况下,我不仅想调用第 3 方提供商来获取用户信息,而且要检查他们的令牌对于单点注销是否仍然有效,并防止多个会话。

    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如果有人对更详细的内容感兴趣,请询问。我可以添加更多。我确实把它弄得太难了,因为现在我明白了,这很容易,但是真的没有很好的例子来说明如何做到这一点。

    【讨论】:

      猜你喜欢
      • 2015-10-09
      • 2023-04-05
      • 1970-01-01
      • 2023-03-31
      • 2020-02-24
      • 1970-01-01
      • 2017-05-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多