Web API 和 SignalR Web 应用程序 - 身份验证和授权
WebAPI & SignalR web application - Authenticating & Authorizing
我有一个 WebAPI
解决方案,我使用 token authentication
,所以流程如下:
- 用户尝试使用
username
和 password
登录
- 如果凭据正确,他将获得一个令牌,以便在以下请求中使用(放置在
AJAX
请求的 header 中)。
现在 SignalR
开始发挥作用了。由于它使用 WebSockets
,因此您无法传递 header。
在寻找解决方案时,我遇到了以下问题:
- 实际上将 header 传递给
SignalR
- 不是一个选项,因为它强制 SignalR
使用 longPolling
。
$.signalR.ajaxDefaults.headers = { Authorization: "Bearer " + token };
将用于验证 WebAPI
调用的相同 token
作为 query string
/或将其存储在 SignalR
的 cookie 中,然后创建以某种方式将令牌展开并扩展为身份的提供者。 I followed this blog post但是我好像漏掉了什么。
再次将令牌作为 query string
/或作为 cookie 传递,但这次创建自定义 Authorize Attribute
到 Authorize
SignalR
集线器或方法。
Again a blog post about this. 此解决方案的问题出在令牌的 Unprotect
方法中。
最后也是最简单的解决方案是同时启用 cookie authentication
,继续使用 bearer token authentication
进行 WebAPI
调用并让 OWIN Middleware
授权调用在集线器上。 (这个解决方案确实有效)。
现在,问题是每当我向 API
它也发送 cookie。
public partial class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context and user manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
app.UseOAuthBearerTokens(OAuthOptions);
}
}
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
即使我这样做了:
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
Authorization: Bearer 2bTw5d8Vf4sKR9MNMqZsxIOPHp5qtXRTny5YEC_y7yWyrDLU0__q8U8Sbo7N7XBjPmxZXP18GRXjDVb3yQ9vpQnWXppRhVA8KDeGg2G5kITMxiOKvGMaKwyUGpORIeZ0UHyP9jA2fX9zPwzsCqHmq-LoGKls0MQNFjXgRGCCCvro5WPMAJcLs0kUoD_2W_TOTy9_T-koobw-DOivnazPo2Z-6kfXaIUuZ1YKdAbcSJKzpyPR_XrCt4Ma2fCf-LcpMPGo4gDFKfxWdId0XtfS9S-5cXmmOmGM4Y6MkAUK8O9sZlVrpmpvV0hjXF2QwfLtQViPyEctbTr1vPBNn014n60APwGSGnbUJBWMvJhqcjI5pWoubCmk7OHJrn052U_F3bDOi2ha1mVjvhVY1XMAuv2c3Pbyng2ZT_VuIQI7HjP4SLzV6JjRctfIPLEh67-DFp585sJkqgfSyM6h_vR2gPA5hDocaFs73Qa22QMaLRrHThU0HM8L3O8HgFl5oJtD
Referer: http://localhost:15379/index.html
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,ro;q=0.6
Cookie: .AspNet.Cookies=E71BnnTMv8JJ4hS9K46Y2yIbGMQCTS4MVBWBXezUYCSGXPbUPNZh98Q0IElQ0zqGyhB7OpYfdh10Kcy2i5GrWGSiALPPtOZUmszfAYrLZwG2JYiU5MSW80OGZVMY3uG2U1aqvvKJpv7eJwJSOoS4meD_3Qy8SwRzTg8feZArAE-REEXSsbPfq4jQBUUbxfDAyuPVRsLNfkn4oIAwZTs85IulRZI5mLnLqOS7VLejMGIWhkuyOWvvISu1pjsP5FMDXNwDkjv2XCaOpRzZYUxBQJzkcdpDjwW_VO2l7HA263NaG_IBqYpLqG57Fi-Lpp1t5Deh2IRB0VuTqAgrkwxifoBDCCWuY9gNz-vNjsCk4kZc8QKxf7el1gu9l38Ouw6K1EZ9y2j6CGWmW1q-DobaK9JXOQEPm_LGyaGPM5to2vchTyjuieZvLBAjxhLKnXdy34Z7MZXLVIwmpSmyPvmbIuH9QzOvTWD-I1AQFJyCDw8
您是否看到使用令牌身份验证的更简单的 SignalR
身份验证方法?这种最终方法(如果我设法抑制发送带有请求的 cookie)在生产中是否可行?
在处理该特定项目时,我最终只使用了 cookie 身份验证和 CSRF,但我仍然对了解如何使用不记名令牌身份验证对 WebApi 和 SignalR 进行身份验证感兴趣。
For a working sample, please see this GitHub repository.
我最终创建了一个 OAuthBearerTokenAuthenticationProvider
class 试图从 cookie 中检索令牌。
public class OAuthBearerTokenAuthenticationProvider : OAuthBearerAuthenticationProvider
{
public override Task RequestToken(OAuthRequestTokenContext context)
{
var tokenCookie = context.OwinContext.Request.Cookies["BearerToken"];
if (!String.IsNullOrEmpty(tokenCookie))
context.Token = tokenCookie;
return Task.FromResult<object>(null);
}
}
下面是 Startup
class 中处理身份验证的方法:
public void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new AuthorizationServerProvider()
};
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()
{
Provider = new OAuthBearerTokenAuthenticationProvider()
});
}
For a working sample, please see this GitHub repository.
希望这在某些时候对某人有所帮助。
我有一个 WebAPI
解决方案,我使用 token authentication
,所以流程如下:
- 用户尝试使用
username
和password
登录
- 如果凭据正确,他将获得一个令牌,以便在以下请求中使用(放置在
AJAX
请求的 header 中)。
现在 SignalR
开始发挥作用了。由于它使用 WebSockets
,因此您无法传递 header。
在寻找解决方案时,我遇到了以下问题:
- 实际上将 header 传递给
SignalR
- 不是一个选项,因为它强制SignalR
使用longPolling
。
$.signalR.ajaxDefaults.headers = { Authorization: "Bearer " + token };
将用于验证
WebAPI
调用的相同token
作为query string
/或将其存储在SignalR
的 cookie 中,然后创建以某种方式将令牌展开并扩展为身份的提供者。 I followed this blog post但是我好像漏掉了什么。再次将令牌作为
query string
/或作为 cookie 传递,但这次创建自定义Authorize Attribute
到Authorize
SignalR
集线器或方法。 Again a blog post about this. 此解决方案的问题出在令牌的Unprotect
方法中。最后也是最简单的解决方案是同时启用
cookie authentication
,继续使用bearer token authentication
进行WebAPI
调用并让OWIN Middleware
授权调用在集线器上。 (这个解决方案确实有效)。
现在,问题是每当我向 API
它也发送 cookie。
public partial class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context and user manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
app.UseOAuthBearerTokens(OAuthOptions);
}
}
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
即使我这样做了:
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
Authorization: Bearer 2bTw5d8Vf4sKR9MNMqZsxIOPHp5qtXRTny5YEC_y7yWyrDLU0__q8U8Sbo7N7XBjPmxZXP18GRXjDVb3yQ9vpQnWXppRhVA8KDeGg2G5kITMxiOKvGMaKwyUGpORIeZ0UHyP9jA2fX9zPwzsCqHmq-LoGKls0MQNFjXgRGCCCvro5WPMAJcLs0kUoD_2W_TOTy9_T-koobw-DOivnazPo2Z-6kfXaIUuZ1YKdAbcSJKzpyPR_XrCt4Ma2fCf-LcpMPGo4gDFKfxWdId0XtfS9S-5cXmmOmGM4Y6MkAUK8O9sZlVrpmpvV0hjXF2QwfLtQViPyEctbTr1vPBNn014n60APwGSGnbUJBWMvJhqcjI5pWoubCmk7OHJrn052U_F3bDOi2ha1mVjvhVY1XMAuv2c3Pbyng2ZT_VuIQI7HjP4SLzV6JjRctfIPLEh67-DFp585sJkqgfSyM6h_vR2gPA5hDocaFs73Qa22QMaLRrHThU0HM8L3O8HgFl5oJtD
Referer: http://localhost:15379/index.html
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,ro;q=0.6
Cookie: .AspNet.Cookies=E71BnnTMv8JJ4hS9K46Y2yIbGMQCTS4MVBWBXezUYCSGXPbUPNZh98Q0IElQ0zqGyhB7OpYfdh10Kcy2i5GrWGSiALPPtOZUmszfAYrLZwG2JYiU5MSW80OGZVMY3uG2U1aqvvKJpv7eJwJSOoS4meD_3Qy8SwRzTg8feZArAE-REEXSsbPfq4jQBUUbxfDAyuPVRsLNfkn4oIAwZTs85IulRZI5mLnLqOS7VLejMGIWhkuyOWvvISu1pjsP5FMDXNwDkjv2XCaOpRzZYUxBQJzkcdpDjwW_VO2l7HA263NaG_IBqYpLqG57Fi-Lpp1t5Deh2IRB0VuTqAgrkwxifoBDCCWuY9gNz-vNjsCk4kZc8QKxf7el1gu9l38Ouw6K1EZ9y2j6CGWmW1q-DobaK9JXOQEPm_LGyaGPM5to2vchTyjuieZvLBAjxhLKnXdy34Z7MZXLVIwmpSmyPvmbIuH9QzOvTWD-I1AQFJyCDw8
您是否看到使用令牌身份验证的更简单的 SignalR
身份验证方法?这种最终方法(如果我设法抑制发送带有请求的 cookie)在生产中是否可行?
在处理该特定项目时,我最终只使用了 cookie 身份验证和 CSRF,但我仍然对了解如何使用不记名令牌身份验证对 WebApi 和 SignalR 进行身份验证感兴趣。
For a working sample, please see this GitHub repository.
我最终创建了一个 OAuthBearerTokenAuthenticationProvider
class 试图从 cookie 中检索令牌。
public class OAuthBearerTokenAuthenticationProvider : OAuthBearerAuthenticationProvider
{
public override Task RequestToken(OAuthRequestTokenContext context)
{
var tokenCookie = context.OwinContext.Request.Cookies["BearerToken"];
if (!String.IsNullOrEmpty(tokenCookie))
context.Token = tokenCookie;
return Task.FromResult<object>(null);
}
}
下面是 Startup
class 中处理身份验证的方法:
public void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new AuthorizationServerProvider()
};
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()
{
Provider = new OAuthBearerTokenAuthenticationProvider()
});
}
For a working sample, please see this GitHub repository.
希望这在某些时候对某人有所帮助。