从OWIN中的OAuth承载令牌获取IPrincipal

本文关键字:令牌 获取 IPrincipal OWIN 中的 OAuth | 更新日期: 2024-09-23 20:06:15

我已经使用OWIN成功地将OAuth添加到我的WebAPI 2项目中。我接收令牌,并可以在HTTP标头中使用它们来访问资源。

现在,我还想在其他通道上使用这些令牌进行身份验证,而这些通道不是OWIN模板所针对的标准HTTP请求。例如,我使用WebSockets,其中客户端必须发送OAuth承载令牌来进行身份验证。

在服务器端,我通过WebSocket接收令牌但是我现在如何将此令牌放入OWIN管道中,以从中提取IPrincipal和ClientIdentifier在WebApi 2模板中,所有这些对我来说都是抽象的,所以我不需要做任何事情来让它工作。

因此,基本上,我将令牌作为字符串,并希望使用OWIN来访问该令牌中编码的用户信息

提前感谢您的帮助。

从OWIN中的OAuth承载令牌获取IPrincipal

我在这篇博客文章中找到了解决方案的一部分:http://leastprivilege.com/2013/10/31/retrieving-bearer-tokens-from-alternative-locations-in-katanaowin/

因此,我创建了自己的提供商,如下所示:

public class QueryStringOAuthBearerProvider : OAuthBearerAuthenticationProvider
{
    public override Task RequestToken(OAuthRequestTokenContext context)
    {
        var value = context.Request.Query.Get("access_token");
        if (!string.IsNullOrEmpty(value))
        {
            context.Token = value;
        }
        return Task.FromResult<object>(null);
    }
}

然后我需要将它添加到Startup.Auth.cs中的应用程序中,如下所示:

OAuthBearerOptions = new OAuthBearerAuthenticationOptions()
{
   Provider = new QueryStringOAuthBearerProvider(),
   AccessTokenProvider = new AuthenticationTokenProvider()
   {
       OnCreate = create,
       OnReceive = receive
   },
};
app.UseOAuthBearerAuthentication(OAuthBearerOptions);

使用自定义AuthenticationTokenProvider,我可以在管道的早期从令牌中检索所有其他值:

public static Action<AuthenticationTokenCreateContext> create = new Action<AuthenticationTokenCreateContext>(c =>
{
    c.SetToken(c.SerializeTicket());
});
public static Action<AuthenticationTokenReceiveContext> receive = new Action<AuthenticationTokenReceiveContext>(c =>
{
    c.DeserializeTicket(c.Token);
    c.OwinContext.Environment["Properties"] = c.Ticket.Properties;
});

现在,例如在我的WebSocket Hander中,我可以检索ClientId和其他类似的内容:

IOwinContext owinContext = context.GetOwinContext();
if (owinContext.Environment.ContainsKey("Properties"))
{
    AuthenticationProperties properties = owinContext.Environment["Properties"] as AuthenticationProperties;
    string clientId = properties.Dictionary["clientId"];
...
 }

默认情况下,OWIN在IIS上托管时使用ASP.NET机器密钥数据保护来保护OAuth访问令牌。可以使用System.Web.dll中的MachineKey类取消对令牌的保护。

public class MachineKeyProtector : IDataProtector
{
    private readonly string[] _purpose =
    {
        typeof(OAuthAuthorizationServerMiddleware).Namespace,
        "Access_Token",
        "v1"
    };
    public byte[] Protect(byte[] userData)
    {
       throw new NotImplementedException();
    }
    public byte[] Unprotect(byte[] protectedData)
    {
        return System.Web.Security.MachineKey.Unprotect(protectedData, _purpose);
    }
}

然后,构造TicketDataFormat以获取AuthenticationTicket对象,您可以在其中获取ClaimsIdentity和AuthenticationProperties。

var access_token="your token here";
var secureDataFormat = new TicketDataFormat(new MachineKeyProtector());
AuthenticationTicket ticket = secureDataFormat.Unprotect(access_token);

要取消对其他OAuth令牌的保护,只需要更改_purpose内容即可。有关详细信息,请参阅此处的OAuthAuthorizationServerMiddleware类:http://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin.Security.OAuth/OAuthAuthorizationServerMiddleware.cs

if (Options.AuthorizationCodeFormat == null)
{
    IDataProtector dataProtecter = app.CreateDataProtector(
        typeof(OAuthAuthorizationServerMiddleware).FullName,
        "Authentication_Code", "v1");
    Options.AuthorizationCodeFormat = new TicketDataFormat(dataProtecter);
}
if (Options.AccessTokenFormat == null)
{
    IDataProtector dataProtecter = app.CreateDataProtector(
        typeof(OAuthAuthorizationServerMiddleware).Namespace,
        "Access_Token", "v1");
    Options.AccessTokenFormat = new TicketDataFormat(dataProtecter);
}
if (Options.RefreshTokenFormat == null)
{
    IDataProtector dataProtecter = app.CreateDataProtector(
        typeof(OAuthAuthorizationServerMiddleware).Namespace,
        "Refresh_Token", "v1");
    Options.RefreshTokenFormat = new TicketDataFormat(dataProtecter);
}

除了johnny qian答案之外,使用此方法更好地创建DataProtectorjohnny qian答案,取决于IIS,在自托管场景中失败。

using Microsoft.Owin.Security.DataProtection;
var dataProtector = app.CreateDataProtector(new string[]   {
     typeof(OAuthAuthorizationServerMiddleware).Namespace,
     "Access_Token",
     "v1"
});

您的令牌是什么样的,是加密字符串还是格式化字符串,格式是什么?

我的代码:

public static Action<AuthenticationTokenReceiveContext> receive = new Action<AuthenticationTokenReceiveContext>(c =>
{
        if (!string.IsNullOrEmpty(c.Token))
        {
            c.DeserializeTicket(c.Token);
            //c.OwinContext.Environment["Properties"] = c.Ticket.Properties;
        }
});

c.票证始终为空。