c# - 使用 AutoFac 将 BL 注入 OAuth
问题描述
我已按照此博客在我的 WebApi 中生成刷新令牌。在 RefreshTokenProvider 类中,他正在访问 AuthenticationRepository 以在表中为生成的刷新令牌创建一行。每件事都完美无缺。但现在我想将依赖注入添加到我的 WebAPI 项目中。对于依赖注入,我使用具有以下配置的 AutoFac
public class IocConfig
{
public static AutofacWebApiDependencyResolver Configure()
{
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<DefaultPrincipalProvider>().As<IPrincipalProvider>();
builder.RegisterType<Logic>().AsSelf().InstancePerRequest();
builder.RegisterType<DataAccess>().AsSelf().InstancePerRequest();
builder.RegisterType<AuthRefreshTokenProvider>().As<IAuthenticationTokenProvider>().SingleInstance();
var container = builder.Build();
var resolver = new AutofacWebApiDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = resolver;
return resolver;
}
}
全球.asax.cs
protected void Application_Start()
{
IocConfig.Configure();
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
控制器
public class ItemController : ApiController
{
private Logic _logic;
public ItemController(Logic logic)
{
_logic = logic;
}
}
商业逻辑
public partial class Logic
{
IPrincipalProvider _principalProvider;
DataAccess _dataAccess;
string _currentUserId;
public Logic(DataAccess dataAccess,IPrincipalProvider provider)
{
_dataAccess = dataAccess;
}
}
数据访问
public partial class DataAccess
{
public DataAccess()
{
}
}
上述配置一切正常,但我坚持如何配置OAuthAuthorizationServerOptions
。我需要将BusinessLogic
实例传递给 AuthRefreshTokenProvider。
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
RefreshTokenProvider = new AuthRefreshTokenProvider(),// Need To use Dependency Injection Here
// In production mode set AllowInsecureHttp = false
AllowInsecureHttp = true
};
AuthRefreshTokenProvider
public class AuthRefreshTokenProvider : IAuthenticationTokenProvider
{
private Logic _logic;
public AuthRefreshTokenProvider(Logic logic)
{
_logic = logic;
}
}
我已经尝试了很多方法来完成这项工作。我知道问题出InstancePerRequest()
在 SingleInstance 内部的实例化中。我一直在阅读很多文章和 stackoverflow 帖子以使其正常工作,但似乎无法使其正常工作
解决方案
如果我正确理解您的问题,您的问题是关于从单例服务上下文访问范围服务?
假设您的应用程序是 ASP.Net WebAPI(不是 Core),您需要捕获HttpRequestMessage
才能访问请求范围。
首先,您需要在某个地方保存请求消息,并且因为您想从单例服务访问请求消息,所以新服务也需要是单例服务:
interface IHttpRequestAccessor
{
HttpRequestMessage Request { get; set; }
}
class HttpRequestAccessor : IHttpRequestAccessor
{
private readonly AsyncLocal<HttpRequestMessageHolder> _currentRequest =
new AsyncLocal<HttpRequestMessageHolder>();
public HttpRequestMessage Request
{
get => _currentRequest.Value?.Value;
set
{
HttpRequestMessageHolder holder = _currentRequest.Value;
if (holder != null)
{
holder.Value = null;
}
if (value != null)
{
_currentRequest.Value = new HttpRequestMessageHolder { Value = value };
}
}
}
private class HttpRequestMessageHolder
{
public HttpRequestMessage Value { get; set; }
}
}
builder.RegisterType<HttpRequestAccessor>()
.As<IHttpRequestAccessor>()
.SingleInstance();
这是如何工作的?
此类公开一个属性以获取和设置HttpRequestMessage
当前异步执行上下文。因为每个请求的数据上下文是不同的,并且在 WebAPI 请求管道的所有步骤中都被继承,所以我们可以将它设置在一个地方,然后在另一个地方为同一个 HTTP 请求使用它。这与IHttpContextAccessor
ASP.Net Core 应用程序中的概念相同。
现在我们需要在某个地方进行捕获和设置IHttpRequestAccessor.Request
。委托处理程序是一个不错的选择:
class CaptureHttpRequestMessageHandler : DelegatingHandler
{
private readonly IHttpRequestAccessor _requestMessageAccessor;
public CaptureHttpRequestMessageHandler(IHttpRequestAccessor requestMessageAccessor)
{
_requestMessageAccessor = requestMessageAccessor;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
if (_requestMessageAccessor != null)
{
_requestMessageAccessor.Request = request;
}
return base.SendAsync(request, cancellationToken);
}
}
并将其添加到配置中:
GlobalConfiguration.Configuration.MessageHandlers.Add(
new CaptureHttpRequestMessageHandler(/* resolve services here */));
毕竟,注入IHttpRequestAccessor
您的AuthRefreshTokenProvider
并删除Logic
.
每当Logic
需要时,使用以下方法即时解决它:
_httpRequestAccessor.Request.GetDependencyScope().GetService(typeof(Logic));
只要在有HTTP 请求AuthRefreshTokenProvider
时调用,这应该可以工作。
推荐阅读
- laravel - 为什么这个 Eloquent 查询没有得到预期的结果?
- flutter - Flutter DropdownButtonFormField.onChanged 不更新 UI
- django - Django 错误,CSRF 失败:CSRF 令牌丢失或不正确
- ruby-on-rails - 仅在条件下保存对象
- python - 如何遍历 itertools.product() 的结果?
- android - 从屏幕截图中获取像素颜色
- javascript - 反应中的多个参考
- xml - cXML 请求 - 未知属性
- python - 如何从我的 Api 向 Xamarin 表单应用程序发送获取请求?
- python - 如何解决掷硬币的输出错误?