我已遵循此Blog在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;
}
}
Global.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);
}
Controller
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;
}
}
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;
}
}
我已经尝试了很多方法来完成这项工作。我知道问题出在SingleInstance的实例化InstancePerRequest()
中。我一直在阅读很多文章和stackoverflow帖子,以使它正常工作,但似乎无法使其工作]
HttpRequestMessage
才能访问请求范围。首先,您需要在某个地方保留请求消息,并且由于您想从单例服务访问请求消息,因此新服务也必须是
singleton服务:
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请求。这与在ASP.Net Core应用中完成IHttpContextAccessor
的概念相同。
IHttpRequestAccessor.Request
。 delegating handler是一个不错的选择: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请求中[[0]时调用AuthRefreshTokenProvider
,它就应该起作用。