Switch to IOptionsMonitor (#1295)
This commit is contained in:
parent
fd502195a4
commit
23da476176
|
|
@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
|
||||||
private string _sessionKey;
|
private string _sessionKey;
|
||||||
private Task<AuthenticateResult> _readCookieTask;
|
private Task<AuthenticateResult> _readCookieTask;
|
||||||
|
|
||||||
public CookieAuthenticationHandler(IOptionsSnapshot<CookieAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
|
public CookieAuthenticationHandler(IOptionsMonitor<CookieAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
|
||||||
: base(options, logger, encoder, clock)
|
: base(options, logger, encoder, clock)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
|
||||||
{
|
{
|
||||||
internal class FacebookHandler : OAuthHandler<FacebookOptions>
|
internal class FacebookHandler : OAuthHandler<FacebookOptions>
|
||||||
{
|
{
|
||||||
public FacebookHandler(IOptionsSnapshot<FacebookOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
|
public FacebookHandler(IOptionsMonitor<FacebookOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
|
||||||
: base(options, logger, encoder, clock)
|
: base(options, logger, encoder, clock)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
|
||||||
{
|
{
|
||||||
internal class GoogleHandler : OAuthHandler<GoogleOptions>
|
internal class GoogleHandler : OAuthHandler<GoogleOptions>
|
||||||
{
|
{
|
||||||
public GoogleHandler(IOptionsSnapshot<GoogleOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
|
public GoogleHandler(IOptionsMonitor<GoogleOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
|
||||||
: base(options, logger, encoder, clock)
|
: base(options, logger, encoder, clock)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
||||||
{
|
{
|
||||||
private OpenIdConnectConfiguration _configuration;
|
private OpenIdConnectConfiguration _configuration;
|
||||||
|
|
||||||
public JwtBearerHandler(IOptionsSnapshot<JwtBearerOptions> options, ILoggerFactory logger, UrlEncoder encoder, IDataProtectionProvider dataProtection, ISystemClock clock)
|
public JwtBearerHandler(IOptionsMonitor<JwtBearerOptions> options, ILoggerFactory logger, UrlEncoder encoder, IDataProtectionProvider dataProtection, ISystemClock clock)
|
||||||
: base(options, logger, encoder, clock)
|
: base(options, logger, encoder, clock)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Authentication.MicrosoftAccount
|
||||||
{
|
{
|
||||||
internal class MicrosoftAccountHandler : OAuthHandler<MicrosoftAccountOptions>
|
internal class MicrosoftAccountHandler : OAuthHandler<MicrosoftAccountOptions>
|
||||||
{
|
{
|
||||||
public MicrosoftAccountHandler(IOptionsSnapshot<MicrosoftAccountOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
|
public MicrosoftAccountHandler(IOptionsMonitor<MicrosoftAccountOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
|
||||||
: base(options, logger, encoder, clock)
|
: base(options, logger, encoder, clock)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
|
||||||
set { base.Events = value; }
|
set { base.Events = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public OAuthHandler(IOptionsSnapshot<TOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
|
public OAuthHandler(IOptionsMonitor<TOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
|
||||||
: base(options, logger, encoder, clock)
|
: base(options, logger, encoder, clock)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
|
||||||
|
|
||||||
protected HtmlEncoder HtmlEncoder { get; }
|
protected HtmlEncoder HtmlEncoder { get; }
|
||||||
|
|
||||||
public OpenIdConnectHandler(IOptionsSnapshot<OpenIdConnectOptions> options, ILoggerFactory logger, HtmlEncoder htmlEncoder, UrlEncoder encoder, ISystemClock clock)
|
public OpenIdConnectHandler(IOptionsMonitor<OpenIdConnectOptions> options, ILoggerFactory logger, HtmlEncoder htmlEncoder, UrlEncoder encoder, ISystemClock clock)
|
||||||
: base(options, logger, encoder, clock)
|
: base(options, logger, encoder, clock)
|
||||||
{
|
{
|
||||||
HtmlEncoder = htmlEncoder;
|
HtmlEncoder = htmlEncoder;
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
||||||
set { base.Events = value; }
|
set { base.Events = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public TwitterHandler(IOptionsSnapshot<TwitterOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
|
public TwitterHandler(IOptionsMonitor<TwitterOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
|
||||||
: base(options, logger, encoder, clock)
|
: base(options, logger, encoder, clock)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.Authentication
|
||||||
|
|
||||||
protected ISystemClock Clock { get; }
|
protected ISystemClock Clock { get; }
|
||||||
|
|
||||||
protected IOptionsSnapshot<TOptions> OptionsSnapshot { get; }
|
protected IOptionsMonitor<TOptions> OptionsMonitor { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The handler calls methods on the events which give the application control at certain points where processing is occurring.
|
/// The handler calls methods on the events which give the application control at certain points where processing is occurring.
|
||||||
|
|
@ -58,12 +58,12 @@ namespace Microsoft.AspNetCore.Authentication
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AuthenticationHandler(IOptionsSnapshot<TOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
|
protected AuthenticationHandler(IOptionsMonitor<TOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
|
||||||
{
|
{
|
||||||
Logger = logger.CreateLogger(this.GetType().FullName);
|
Logger = logger.CreateLogger(this.GetType().FullName);
|
||||||
UrlEncoder = encoder;
|
UrlEncoder = encoder;
|
||||||
Clock = clock;
|
Clock = clock;
|
||||||
OptionsSnapshot = options;
|
OptionsMonitor = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -86,7 +86,7 @@ namespace Microsoft.AspNetCore.Authentication
|
||||||
Scheme = scheme;
|
Scheme = scheme;
|
||||||
Context = context;
|
Context = context;
|
||||||
|
|
||||||
Options = OptionsSnapshot.Get(Scheme.Name) ?? new TOptions();
|
Options = OptionsMonitor.Get(Scheme.Name) ?? new TOptions();
|
||||||
Options.Validate();
|
Options.Validate();
|
||||||
|
|
||||||
await InitializeEventsAsync();
|
await InitializeEventsAsync();
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Authentication
|
||||||
set { base.Events = value; }
|
set { base.Events = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected RemoteAuthenticationHandler(IOptionsSnapshot<TOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
|
protected RemoteAuthenticationHandler(IOptionsMonitor<TOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
|
||||||
: base(options, logger, encoder, clock) { }
|
: base(options, logger, encoder, clock) { }
|
||||||
|
|
||||||
protected override Task<object> CreateEventsAsync()
|
protected override Task<object> CreateEventsAsync()
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,42 @@ namespace Microsoft.AspNetCore.Authentication
|
||||||
{
|
{
|
||||||
public class DynamicSchemeTests
|
public class DynamicSchemeTests
|
||||||
{
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task OptionsAreConfiguredOnce()
|
||||||
|
{
|
||||||
|
var server = CreateServer(s =>
|
||||||
|
{
|
||||||
|
s.Configure<TestOptions>("One", o => o.Instance = new Singleton());
|
||||||
|
s.Configure<TestOptions>("Two", o => o.Instance = new Singleton());
|
||||||
|
});
|
||||||
|
// Add One scheme
|
||||||
|
var response = await server.CreateClient().GetAsync("http://example.com/add/One");
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
var transaction = await server.SendAsync("http://example.com/auth/One");
|
||||||
|
Assert.Equal("One", transaction.FindClaimValue(ClaimTypes.NameIdentifier, "One"));
|
||||||
|
Assert.Equal("1", transaction.FindClaimValue("Count"));
|
||||||
|
|
||||||
|
// Verify option is not recreated
|
||||||
|
transaction = await server.SendAsync("http://example.com/auth/One");
|
||||||
|
Assert.Equal("One", transaction.FindClaimValue(ClaimTypes.NameIdentifier, "One"));
|
||||||
|
Assert.Equal("1", transaction.FindClaimValue("Count"));
|
||||||
|
|
||||||
|
// Add Two scheme
|
||||||
|
response = await server.CreateClient().GetAsync("http://example.com/add/Two");
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
transaction = await server.SendAsync("http://example.com/auth/Two");
|
||||||
|
Assert.Equal("Two", transaction.FindClaimValue(ClaimTypes.NameIdentifier, "Two"));
|
||||||
|
Assert.Equal("2", transaction.FindClaimValue("Count"));
|
||||||
|
|
||||||
|
// Verify options are not recreated
|
||||||
|
transaction = await server.SendAsync("http://example.com/auth/One");
|
||||||
|
Assert.Equal("One", transaction.FindClaimValue(ClaimTypes.NameIdentifier, "One"));
|
||||||
|
Assert.Equal("1", transaction.FindClaimValue("Count"));
|
||||||
|
transaction = await server.SendAsync("http://example.com/auth/Two");
|
||||||
|
Assert.Equal("Two", transaction.FindClaimValue(ClaimTypes.NameIdentifier, "Two"));
|
||||||
|
Assert.Equal("2", transaction.FindClaimValue("Count"));
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task CanAddAndRemoveSchemes()
|
public async Task CanAddAndRemoveSchemes()
|
||||||
{
|
{
|
||||||
|
|
@ -48,7 +84,6 @@ namespace Microsoft.AspNetCore.Authentication
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("http://example.com/auth/Two"));
|
await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("http://example.com/auth/Two"));
|
||||||
await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("http://example.com/auth/One"));
|
await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("http://example.com/auth/One"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -69,9 +104,27 @@ namespace Microsoft.AspNetCore.Authentication
|
||||||
await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("http://example.com/auth"));
|
await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("http://example.com/auth"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestHandler : AuthenticationHandler<AuthenticationSchemeOptions>
|
public class TestOptions : AuthenticationSchemeOptions
|
||||||
{
|
{
|
||||||
public TestHandler(IOptionsSnapshot<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
|
public Singleton Instance { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Singleton
|
||||||
|
{
|
||||||
|
public static int _count;
|
||||||
|
|
||||||
|
public Singleton()
|
||||||
|
{
|
||||||
|
_count++;
|
||||||
|
Count = _count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestHandler : AuthenticationHandler<TestOptions>
|
||||||
|
{
|
||||||
|
public TestHandler(IOptionsMonitor<TestOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,12 +133,16 @@ namespace Microsoft.AspNetCore.Authentication
|
||||||
var principal = new ClaimsPrincipal();
|
var principal = new ClaimsPrincipal();
|
||||||
var id = new ClaimsIdentity();
|
var id = new ClaimsIdentity();
|
||||||
id.AddClaim(new Claim(ClaimTypes.NameIdentifier, Scheme.Name, ClaimValueTypes.String, Scheme.Name));
|
id.AddClaim(new Claim(ClaimTypes.NameIdentifier, Scheme.Name, ClaimValueTypes.String, Scheme.Name));
|
||||||
|
if (Options.Instance != null)
|
||||||
|
{
|
||||||
|
id.AddClaim(new Claim("Count", Options.Instance.Count.ToString()));
|
||||||
|
}
|
||||||
principal.AddIdentity(id);
|
principal.AddIdentity(id);
|
||||||
return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(principal, new AuthenticationProperties(), Scheme.Name)));
|
return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(principal, new AuthenticationProperties(), Scheme.Name)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TestServer CreateServer(Action<AuthenticationOptions> configureAuth = null)
|
private static TestServer CreateServer(Action<IServiceCollection> configureServices = null)
|
||||||
{
|
{
|
||||||
var builder = new WebHostBuilder()
|
var builder = new WebHostBuilder()
|
||||||
.Configure(app =>
|
.Configure(app =>
|
||||||
|
|
@ -122,11 +179,8 @@ namespace Microsoft.AspNetCore.Authentication
|
||||||
})
|
})
|
||||||
.ConfigureServices(services =>
|
.ConfigureServices(services =>
|
||||||
{
|
{
|
||||||
if (configureAuth == null)
|
configureServices?.Invoke(services);
|
||||||
{
|
services.AddAuthentication();
|
||||||
configureAuth = o => { };
|
|
||||||
}
|
|
||||||
services.AddAuthentication(configureAuth);
|
|
||||||
});
|
});
|
||||||
return new TestServer(builder);
|
return new TestServer(builder);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue