(在这个问题的底部添加了更新)
我有一个 Web 应用程序,它使用 MVC5 和 WebAPI2 以及 Autofac for DI。该应用程序使用 ASP.NET Identity 和 oAuth 不记名令牌,尽管后者可能不是重点。这一切都运行得很好,但此时我需要在整个 OWIN 管道以及应用程序的其余部分共享注入服务的相同实例,因此我正在尝试为 MVC 和 Web 设置 Autofac 的 OWIN 集成API。我似乎很接近 - 一切似乎都有效,除了AuthorizeAttibutes
on ApiControllers
。 oAuth 过程成功完成,我最终使用不记名令牌登录,但随后尝试在 WebAPI 控制器/操作上使用所述令牌进行授权失败。
具体来说,在IsAuthorized
的方法System.Web.Http.AuthorizeAttribute
, IPrincipal.Identity
似乎它没有被正确实例化,因为它没有适当的声明和IsAuthenticated
属性总是假的。 Autofac 的开发者表示此属性应与 OWIN 集成一起使用 https://github.com/autofac/Autofac/issues/509,即使该代码使用GlobalConfiguration
这对于 OWIN 集成来说是不可取的 http://docs.autofac.org/en/latest/integration/webapi.html#owin-integration。我看到了多个删除建议config.SuppressDefaultHostAuthentication()
(here https://stackoverflow.com/questions/23785528/user-iprincipal-not-avaliable-on-apicontrollers-constructor-using-web-api-2-1 and here https://stackoverflow.com/questions/27294032/webapi-owin-identity-is-not-authorized-after-signing-in),虽然不建议这样做,但我出于绝望而尝试过,但没有成功——对于我的特定配置,这会导致 IPrincipal 返回为空。我也尝试过修改一个更简单的示例项目 https://github.com/AkosLukacs/Autofac-OWIN-MVC比我自己用的AuthorizeAttribute
在 WebAPI 控制器上,也没有成功。此时我已经没有什么可尝试的了,非常感谢您的帮助。
这是我的 Startup.cs:
[assembly: OwinStartup(typeof (Startup))]
namespace Project.Web
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
var config = new HttpConfiguration();
builder.RegisterHttpRequestMessage(config);
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
RegisterGeneralTypes(builder);
var container = builder.Build();
WebApiConfig.Register(config);
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
WebApiFilterConfig.RegisterGlobalFilters(config.Filters);
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
app.UseAutofacMvc();
app.UseWebApi(config);
ConfigureAuth(app);
}
private static void RegisterGeneralTypes(ContainerBuilder builder)
{
builder.Register(c => new DomainModelContext())
.AsSelf()
.InstancePerRequest();
builder.Register(c => HttpContext.Current.User.Identity)
.As(typeof (IIdentity));
builder.RegisterType<EmailService>()
.AsImplementedInterfaces()
.InstancePerRequest();
builder.Register(c => new IdentityFactoryOptions<DomainUserManager>
{
DataProtectionProvider = DataProtectionProvider
}).InstancePerRequest();
builder.RegisterType<DomainUserManager>()
.AsSelf()
.UsingConstructor(typeof (IIdentityMessageService),
typeof (IdentityFactoryOptions<DomainUserManager>),
typeof (CustomUserStore))
.InstancePerRequest();
builder.RegisterType<CustomUserStore>()
.AsImplementedInterfaces()
.AsSelf()
.InstancePerRequest();
builder.Register(c => HttpContext.Current.GetOwinContext().Authentication)
.As<IAuthenticationManager>();
}
}
}
和我的 Startup.Auth.cs:
public partial class Startup
{
internal static IDataProtectionProvider DataProtectionProvider;
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
public void ConfigureAuth(IAppBuilder app)
{
var onValidateIdentity = SecurityStampValidator
.OnValidateIdentity<DomainUserManager, DomainUser, int>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentityCallback: (manager, user) =>
user.GenerateUserIdentityAsync(manager, CookieAuthenticationDefaults.AuthenticationType),
getUserIdCallback: id => id.GetUserId<int>());
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
LoginPath = new PathString("/account/login"),
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = onValidateIdentity
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/v1/account/externallogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
DataProtectionProvider = app.GetDataProtectionProvider();
}
}
我认为这涵盖了它,但我很乐意根据要求发布额外的代码。
UPDATE
所以基于朱穆罗的回答 https://stackoverflow.com/questions/37826551/authorization-with-asp-net-identity-autofac-owin-integration/37839448#37839448,我按照建议更改了注册顺序。然而,这只是将完全相同的问题从 Web API 授权转移到 MVC 授权。由于我在更新之前就已经使用了 MVC 身份验证,因此我最终尝试在管道中注册身份验证两次,如下所示:
app.UseAutofacMiddleware(container);
ConfigureAuth(app);
app.UseAutofacWebApi(config);
app.UseAutofacMvc();
app.UseWebApi(config);
ConfigureAuth(app);
这是可行的,但我真的不能说我理解为什么,而且我无法想象这样做两次是好的。所以现在我有新的问题:
- WebAPI 需要在 中注册 Auth,这是有道理的
首先是管道,但为什么 MVC 要我注册
授权last?
- 我怎样才能清理这个并避免打电话
ConfigureAuth
twice?