从 OWIN 中的 OAuth Bearer Token 获取 IPrincipal
Posted
技术标签:
【中文标题】从 OWIN 中的 OAuth Bearer Token 获取 IPrincipal【英文标题】:Get IPrincipal from OAuth Bearer Token in OWIN 【发布时间】:2014-01-02 08:45:55 【问题描述】:我已使用 OWIN 成功地将 OAuth 添加到我的 WebAPI 2 项目中。我收到令牌并可以在 HTTP 标头中使用它们来访问资源。
现在我想在其他通道上使用这些令牌进行身份验证,这些通道不是 OWIN 模板所针对的标准 HTTP 请求。例如,我使用 WebSockets,客户端必须发送 OAuth Bearer Token 进行身份验证。
在服务器端,我通过 WebSocket 接收令牌。 但是我现在如何将此令牌放入 OWIN 管道中以从中提取 IPrincipal 和 ClientIdentifier? 在 WebApi 2 模板中,所有这些对我来说都是抽象的,所以我无需做任何事情让它工作。
所以,基本上,我将令牌作为字符串,并希望使用 OWIN 访问在该令牌中编码的用户信息。
提前感谢您的帮助。
【问题讨论】:
【参考方案1】:我在这篇博文中找到了部分解决方案:http://leastprivilege.com/2013/10/31/retrieving-bearer-tokens-from-alternative-locations-in-katanaowin/
所以我创建了自己的Provider如下:
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"];
...
【讨论】:
不知道你是怎么想出来的。我找不到任何关于它的文档,但非常感谢!【参考方案2】:默认情况下,当托管在 IIS 上时,OWIN 使用 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);
【讨论】:
所以这意味着您必须在 webapi 和其他应用程序(比如一些独立的 signalR 控制台应用程序)上使用相同的保护程序? 那么我们无法访问 System.Web 的自托管 owin 应用程序呢? @MahmoudMoravej 然后你必须使用 DPAPI DataProtector 而不是 MachineKeyDataProtector。 是的,就像我在下面的答案中解释的那样【参考方案3】:除了johnny-qian的回答,用这种方法创建DataProtector更好。 johnny-qian 答案,取决于 IIS,在自托管方案中失败。
using Microsoft.Owin.Security.DataProtection;
var dataProtector = app.CreateDataProtector(new string[]
typeof(OAuthAuthorizationServerMiddleware).Namespace,
"Access_Token",
"v1"
);
【讨论】:
【参考方案4】:你的令牌是什么样的,是加密字符串还是格式化字符串,格式是什么?
我的代码:
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.Ticket 始终为空。
【讨论】:
以上是关于从 OWIN 中的 OAuth Bearer Token 获取 IPrincipal的主要内容,如果未能解决你的问题,请参考以下文章
Web API 2 OWIN Bearer Token cookie的用途?
在 WebAPI 的查询字符串中传递和验证 OWIN Bearer 令牌