You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The old 1.0 Authentication stack no longer will work, and is obsolete in 2.0. All authentication related functionality must be migrated to the 2.0 stack, any interop between old and new must be side by side apps, as opposed to mixing 1.0 auth code with 2.0 auth code in the same app. Cookie authentication will interop, so 1.0 Cookies and 2.0 Cookies will be valid in both apps if configured properly. The main motivation was to move to a more flexible service based IAuthenticationService and away from the old middleware/IAuthenticationManager design that came over from Microsoft.Owin.
IAuthenticationManager(aka httpContext.Authentication) is now obsolete
This was the main entry point into the old auth system. This has now been replaced with a new set of HttpContext extensions that live in the Microsoft.AspNetCore.Authentication namespace and remain very similar:
// Add using to pickup the new extension methodsusing Microsoft.AspNetCore.Authentication;// Update by just removing the .Authentication
context.Authentication.AuthenticateAsync =>context.AuthenticateAsynccontext.Authentication.ChallengeAsync => context.ChallengeAsync
Configure(): UseXyzAuthentication has been replaced by ConfigureService(): AddXyz()
In Auth 1.0, every auth scheme had its own middleware, and startup looked something like this:
In Auth 2.0, there is now only a single Authentication middleware, and each authentication scheme is registered during ConfigureServices, and UseIdentity() is no longer required (since it was just calling UseCookie 4 times underneath the covers)
publicvoidConfigureServices(IServiceCollectionservices){
services.AddIdentity<ApplicationUser,IdentityRole>().AddEntityFrameworkStores();// If you want to tweak identity cookies, they no longer are part of identityOptions
services.ConfigureApplicationCookie(o => o.LoginPath =new PathString("/login");
services.AddAuthentication().AddFacebook(o =>{ o.AppId = Configuration["facebook:appid"]; o.AppSecret = Configuration["facebook:appsecret"];});}publicvoidConfigure(IApplicationBuilderapp,ILoggerFactoryloggerfactory){
app.UseAuthentication();}
New Microsoft.AspNetCore.Authentication.Core/Abstractions
All of the old Authentication namespaces in HttpAbstractions have been deprecated. The new Auth 2.0 stack lives in two new packages inside the HttpAbstractions repo: Microsoft.AspNetCore.Authentication.Core/Abstractions.
Brief overview:
IAuthenticationService: used by the HttpContext extension methods to expose the 5 main operations Authenticate/Challenge/Forbid/SignIn/SignOut
IAuthenticationHandler: Defines the required operations for all handlers: Authenticate/Challenge/Forbid
IAuthenticationSignIn/OutHandler: Implemented to add the SignIn/SignOut methods respectively
IAuthenticationRequestHandler: Implemented by handlers that need to participate in request handler, i.e. remote authentication schemes like OAuth/OIDC that need to process 3rd party auth responses.
AuthenticationScheme: represents a logical named authentication scheme to target for any given IAuthenticationService method, it binds the scheme name (and optional display name) to an IAuthenticationHandler which implements the scheme specific logic.
IAuthenticationSchemeProvider: responsible for managing which schemes are supported, and what the defaults are for each operation (the default implementation just reads from the AuthenticationOptions)
IAuthenticationHandlerProvider: responsible for returning the correct handler instance for a given scheme and request.
IAuthenticationFeature: used to capture the original request path/pathbase so redirects can be computed property after an app.Map()
Types that are mostly unchanged, just with new homes:
AuthenticationProperties: metadata for authentication operations.
AuthenticationTicket: used to store a claims principal (user) + authentication properties
AuthenticateResult: return value for AuthenticateAsync, contains either a ticket, or a failure
All of the core abstractions and services for authentication live in HttpAbstracions, but there's an additional layer of base classes/functionality targeted towards implementation of AuthenticationHandlers. This is also where the AuthenticationMiddleware lives. The handlers themselves for the various implementations aren't drastically different, but there were a fair amount of changes
Microsoft.AspNetCore.Authentication
Overview:
AuthenticationMiddleware: UseAuthentication() adds this middleware which does two things. By default It will automatically Authenticate using AuthenticationOptions.DefaultAuthenticateScheme to set httpContext.User if specified. It also will give IAuthenticationRequestHandler's a chance to handle the request.
AuthenticationSchemeOptions: Base class for options used with the AuthenticationHandler base class, it defines two common properties in Events and ClaimsIssuer, as well as a virtual Validate() method that will be called on every request by the handler.
AuthenticationHandler<TOptions>: Abstract base class for handlers who must implement HandleAuthenticateAsync. The rest of IAuthenticationHandler is implemented with some reasonable defaults, Challenge(401)/Forbid(403), and logic to handle per request initialization using IOptionsMonitor<TOptions>.Get(authenticationScheme.Name) to resolve the handler's options.
RemoteAuthenticationHandler<TOptions>: Adds the abstract HandleRemoteAuthenticateAsync and implements HandleAuthenticateAsync to call this method. This is meant to be used for 3rd party authentication, i.e. OAuth/OIDC. It adds an additional constraint to TOptions that requires them to be RemoteAuthenticationOptions which adds a bunch of settings like CallbackPath, CorrelationCookie, Backchannel which are needed to talk to a remote authentication provider.
AuthenticationBuilder: is a new class which is used to group all of the AddXyz() authentication methods. This is returned by services.AddAuthentication() and is where specific authentication methods are expected to add themselves as extension methods, i.e. AddCookie(), AddGoogle(), AddFacebook().
Configuring Identity / application cookies
The cookie options that used to be configured via:
Thanks mostly to @PinpointTownes determination to improve the events story, we've refactored and renamed some things to improve the events experience (caveat: if you don't like the names we picked, don't blame @PinpointTownes we overruled him on naming)
At a high level, there 3 main kinds of events:
BaseContext events which are the simplest and just expose properties with no real control flow.
ResultContext events which revolve around producing AuthenticateResults which expose:
Success(): used to indicate that authentication was successful and to use the Principal/Properties in the event to construct the result.
NoResult(): used to indicate no authentication result is to be returned.
Fail(): used to return a failure.
HandleRequestContext events are used in the IAuthenticationRequestHandler/HandleRemoteAuthenticate methods and adds two more methods:
HandleResponse(): used to indicate that the response was generated and the AuthenticationMiddleware should not invoke the rest of the middlewares in the pipeline after it.
SkipHandler() used to indicate that this handler is done with the request, but subsequent handlers will be called, as well as any other middleware in the pipeline if none of those handlers handle the request.
AutomaticAuthentication/Challenge have been replaced by Default[Authenticate/Challenge]Scheme
AutomaticAuthentication/Challenge were intended to only be set on one authentication scheme, but there was no good way to enforce this in 1.0. These have been removed as flags on the individual AuthenticationOptions, and have been moved into the base AuthenticationOptions which can be configured in the call to AddAuthentication(authenticationOptions => authenticationOptions.DefaultScheme = "Cookies").
There are now overloads that use the default schemes for each method in IAuthenticationService
DefaultScheme: if specified, all the other defaults will fallback to this value
DefaultAuthenticateScheme: if specified, AuthenticateAsync() will use this scheme, and also the AuthenticationMiddleware added by UseAuthentication() will use this scheme to set context.User automatically. (Corresponds to AutomaticAuthentication)
DefaultChallengeScheme if specified, ChallengeAsync() will use this scheme, [Authorize] with policies that don't specify schemes will also use this
DefaultSignInScheme is used by SignInAsync() and also by all of the remote auth schemes like Google/Facebook/OIDC/OAuth, typically this would be set to a cookie.
DefaultSignOutScheme is used by SignOutAsync() falls back to DefaultSignInScheme
DefaultForbidScheme is used by ForbidAsync(), falls back to DefaultChallengeScheme
"Windows" Authentication(HttpSys/IISIntegration)
The host behavior hasn't changed too much, but now they each register a single "Windows" authentication scheme. Also IISIntegration now conditionally registers the handler only if windows auth is enabled in IIS (if you have the latest version of ANCM, otherwise it's always registered as before).
Authorization changes
IAuthorizationService.AuthorizeAsync now returns AuthorizationResult instead of bool
In order to enable scenarios around authorization failures, IAuthorizationService now returns a result object which allows access to the reasons why AuthorizeAsync failed (either context.Fail(), or a list of failed requirements)
Removal of ChallengeBehavior => new PolicyEvaluator
In Auth 1.0, there was a ChallengeBehavior enum that was used to specify either Automatic/Unauthorized/Forbid behaviors to signal to the auth middleware what behavior the caller wanted. Automatic was the default and would go down the Forbid(403) code path if the middleware already had an authentication ticket, otherwise would result in Unauthorized(401).
In Auth 2.0, this behavior has been moved into a new Authorization.Policy package, which introduces the IPolicyEvaluator which uses both IAuthenticationService (when requested via policy.AuthenticationSchemes), and IAuthorizationService to decide whether to return a tri state PolicyAuthorizationResult (Succeeded/Challenged/Forbidden).
Overview of [Authorize]
The [Authorize] attribute hasn't changed much, but the there were some implementation details that have changed significantly in MVC's AuthorizeFilter, and here's an overview of how things work: AuthorizeFilter source
An effective policy is computed by combining all of the requested policies/requirements from all relevant [Authorize] attributes on the controller/method/globally.
IPolicyEvaluator.AuthenticateAsync(policy, httpContext) is called, by default, if the has specified any policy.AuthenticationSchemes, AuthenticateAsync will be called on each scheme, and each resulting ClaimsPrincipal will be merged together into a single ClaimsPrincipal set on context.User. If no schemes were specified, the evaluator will attempt to use context.User if it contains an authenticated user. This is usually the normal code path, as DefaultScheme/DefaultAuthenticateScheme will be set to the main application cookie, and the AuthenticationMiddleware will have already set context.User using this scheme's AuthenticateAsync() Authenticate logic
If AllowAnoynmous was specified, authorization is skipped, and the filter logic short circuits and is done.
Finally, IPolicyEvaluator.AuthenticateAsync(policy, authenticationResult, httpContext) is called with the result from step 2. This just basically turns into a call to IAuthorizationService.AuthorizeAsync, and the result is used to determine the appropriate Challenge/ForbidResult if needed.
Claims Transformation
Simpler, new IClaimsTransformation service with a single method: Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
We call this on any successful AuthenticateAsync call.
services.AddSingleton<IClaimsTransformation,ClaimsTransformer>();privateclassClaimsTransformer:IClaimsTransformation{// Can consume services from DI as needed, including scoped DbContextspublicClaimsTransformer(IHttpContextAccessorhttpAccessor){}publicTask<ClaimsPrincipal>TransformAsync(ClaimsPrincipalp){
p.AddIdentity(new ClaimsIdentity());return Task.FromResult(p);}}
How to replicate branched auth middleware functionality in 2.0
It turns out a massive amount of people are not using the AuthenticationSchemes property on the AuthorizeAttribute and instead are using middleware branching to select the current scheme for a request based on some logic (most commonly a path prefix /api).
UPDATE: I should point out that if you're using this middleware and the user isn't authorized, the challenge/forbid issued will end up being the default scheme. If none is set, an exception will be thrown.
Known issues/breaking changes:
In 1.0, it was possible to configure different Authentication middleware with branching, this is no longer possible with a single middleware and shared services across all branches. A workaround could be to use different schemes/options for each branch.
Auth 2.0 now uses IOptionsMonitor and named options, this introduces a breaking change for any apps that were configuring auth using a custom IConfigureOptions. These will need to be updated to implement IConfigureNamedOptions instead, which just means adding an additional public get/set Name property.
The text was updated successfully, but these errors were encountered:
Summary:
The old 1.0 Authentication stack no longer will work, and is obsolete in 2.0. All authentication related functionality must be migrated to the 2.0 stack, any interop between old and new must be side by side apps, as opposed to mixing 1.0 auth code with 2.0 auth code in the same app. Cookie authentication will interop, so 1.0 Cookies and 2.0 Cookies will be valid in both apps if configured properly. The main motivation was to move to a more flexible service based
IAuthenticationService
and away from the old middleware/IAuthenticationManager
design that came over from Microsoft.Owin.For discussion/questions/help, please start with aspnet/Security#1338
IAuthenticationManager
(akahttpContext.Authentication
) is now obsoleteThis was the main entry point into the old auth system. This has now been replaced with a new set of
HttpContext
extensions that live in theMicrosoft.AspNetCore.Authentication
namespace and remain very similar:Configure():
UseXyzAuthentication
has been replaced by ConfigureService(): AddXyz()In Auth 1.0, every auth scheme had its own middleware, and startup looked something like this:
In Auth 2.0, there is now only a single Authentication middleware, and each authentication scheme is registered during
ConfigureServices
, andUseIdentity()
is no longer required (since it was just calling UseCookie 4 times underneath the covers)New
Microsoft.AspNetCore.Authentication.Core/Abstractions
All of the old Authentication namespaces in HttpAbstractions have been deprecated. The new Auth 2.0 stack lives in two new packages inside the HttpAbstractions repo:
Microsoft.AspNetCore.Authentication.Core/Abstractions
.Brief overview:
IAuthenticationService
: used by theHttpContext
extension methods to expose the 5 main operationsAuthenticate/Challenge/Forbid/SignIn/SignOut
IAuthenticationHandler
: Defines the required operations for all handlers: Authenticate/Challenge/ForbidIAuthenticationSignIn/OutHandler
: Implemented to add the SignIn/SignOut methods respectivelyIAuthenticationRequestHandler
: Implemented by handlers that need to participate in request handler, i.e. remote authentication schemes like OAuth/OIDC that need to process 3rd party auth responses.AuthenticationScheme
: represents a logical named authentication scheme to target for any givenIAuthenticationService
method, it binds the scheme name (and optional display name) to anIAuthenticationHandler
which implements the scheme specific logic.IAuthenticationSchemeProvider
: responsible for managing which schemes are supported, and what the defaults are for each operation (the default implementation just reads from theAuthenticationOptions
)IAuthenticationHandlerProvider
: responsible for returning the correct handler instance for a given scheme and request.IAuthenticationFeature
: used to capture the original request path/pathbase so redirects can be computed property after anapp.Map()
Types that are mostly unchanged, just with new homes:
AuthenticationProperties
: metadata for authentication operations.AuthenticationTicket
: used to store a claims principal (user) + authentication propertiesAuthenticateResult
: return value forAuthenticateAsync
, contains either a ticket, or a failureSecurity repo:
Microsoft.AspNetCore.Authentication
/ AuthenticationHandler changesAll of the core abstractions and services for authentication live in HttpAbstracions, but there's an additional layer of base classes/functionality targeted towards implementation of AuthenticationHandlers. This is also where the AuthenticationMiddleware lives. The handlers themselves for the various implementations aren't drastically different, but there were a fair amount of changes
Microsoft.AspNetCore.Authentication
Overview:
AuthenticationMiddleware
:UseAuthentication()
adds this middleware which does two things. By default It will automatically Authenticate usingAuthenticationOptions.DefaultAuthenticateScheme
to sethttpContext.User
if specified. It also will giveIAuthenticationRequestHandler's
a chance to handle the request.AuthenticationSchemeOptions
: Base class for options used with theAuthenticationHandler
base class, it defines two common properties in Events and ClaimsIssuer, as well as a virtualValidate()
method that will be called on every request by the handler.AuthenticationHandler<TOptions>
: Abstract base class for handlers who must implementHandleAuthenticateAsync
. The rest ofIAuthenticationHandler
is implemented with some reasonable defaults, Challenge(401)/Forbid(403), and logic to handle per request initialization usingIOptionsMonitor<TOptions>.Get(authenticationScheme.Name)
to resolve the handler's options.RemoteAuthenticationHandler<TOptions>
: Adds the abstractHandleRemoteAuthenticateAsync
and implementsHandleAuthenticateAsync
to call this method. This is meant to be used for 3rd party authentication, i.e. OAuth/OIDC. It adds an additional constraint to TOptions that requires them to beRemoteAuthenticationOptions
which adds a bunch of settings like CallbackPath, CorrelationCookie, Backchannel which are needed to talk to a remote authentication provider.AuthenticationBuilder
: is a new class which is used to group all of the AddXyz() authentication methods. This is returned byservices.AddAuthentication()
and is where specific authentication methods are expected to add themselves as extension methods, i.e. AddCookie(), AddGoogle(), AddFacebook().Configuring Identity / application cookies
The cookie options that used to be configured via:
now are configured via:
Event changes overview
At a high level, there 3 main kinds of events:
BaseContext
events which are the simplest and just expose properties with no real control flow.ResultContext
events which revolve around producingAuthenticateResult
s which expose:Success()
: used to indicate that authentication was successful and to use the Principal/Properties in the event to construct the result.NoResult()
: used to indicate no authentication result is to be returned.Fail()
: used to return a failure.HandleRequestContext
events are used in the IAuthenticationRequestHandler/HandleRemoteAuthenticate methods and adds two more methods:HandleResponse()
: used to indicate that the response was generated and the AuthenticationMiddleware should not invoke the rest of the middlewares in the pipeline after it.SkipHandler()
used to indicate that this handler is done with the request, but subsequent handlers will be called, as well as any other middleware in the pipeline if none of those handlers handle the request.AutomaticAuthentication/Challenge
have been replaced byDefault[Authenticate/Challenge]Scheme
AutomaticAuthentication/Challenge
were intended to only be set on one authentication scheme, but there was no good way to enforce this in 1.0. These have been removed as flags on the individual AuthenticationOptions, and have been moved into the base AuthenticationOptions which can be configured in the call toAddAuthentication(authenticationOptions => authenticationOptions.DefaultScheme = "Cookies")
.There are now overloads that use the default schemes for each method in
IAuthenticationService
DefaultScheme
: if specified, all the other defaults will fallback to this valueDefaultAuthenticateScheme
: if specified,AuthenticateAsync()
will use this scheme, and also theAuthenticationMiddleware
added byUseAuthentication()
will use this scheme to setcontext.User
automatically. (Corresponds to AutomaticAuthentication)DefaultChallengeScheme
if specified,ChallengeAsync()
will use this scheme,[Authorize]
with policies that don't specify schemes will also use thisDefaultSignInScheme
is used bySignInAsync()
and also by all of the remote auth schemes like Google/Facebook/OIDC/OAuth, typically this would be set to a cookie.DefaultSignOutScheme
is used bySignOutAsync()
falls back toDefaultSignInScheme
DefaultForbidScheme
is used byForbidAsync()
, falls back toDefaultChallengeScheme
"Windows" Authentication(HttpSys/IISIntegration)
The host behavior hasn't changed too much, but now they each register a single "Windows" authentication scheme. Also IISIntegration now conditionally registers the handler only if windows auth is enabled in IIS (if you have the latest version of ANCM, otherwise it's always registered as before).
Authorization changes
IAuthorizationService.AuthorizeAsync
now returnsAuthorizationResult
instead of boolIn order to enable scenarios around authorization failures,
IAuthorizationService
now returns a result object which allows access to the reasons whyAuthorizeAsync
failed (eithercontext.Fail()
, or a list of failed requirements)Removal of
ChallengeBehavior
=> newPolicyEvaluator
In Auth 1.0, there was a
ChallengeBehavior
enum that was used to specify either Automatic/Unauthorized/Forbid behaviors to signal to the auth middleware what behavior the caller wanted. Automatic was the default and would go down the Forbid(403) code path if the middleware already had an authentication ticket, otherwise would result in Unauthorized(401).In Auth 2.0, this behavior has been moved into a new Authorization.Policy package, which introduces the
IPolicyEvaluator
which uses bothIAuthenticationService
(when requested via policy.AuthenticationSchemes), andIAuthorizationService
to decide whether to return a tri statePolicyAuthorizationResult
(Succeeded/Challenged/Forbidden).Overview of
[Authorize]
The
[Authorize]
attribute hasn't changed much, but the there were some implementation details that have changed significantly in MVC'sAuthorizeFilter
, and here's an overview of how things work:AuthorizeFilter source
[Authorize]
attributes on the controller/method/globally.IPolicyEvaluator.AuthenticateAsync(policy, httpContext)
is called, by default, if the has specified anypolicy.AuthenticationSchemes
,AuthenticateAsync
will be called on each scheme, and each resultingClaimsPrincipal
will be merged together into a single ClaimsPrincipal set on context.User. If no schemes were specified, the evaluator will attempt to use context.User if it contains an authenticated user. This is usually the normal code path, asDefaultScheme/DefaultAuthenticateScheme
will be set to the main application cookie, and theAuthenticationMiddleware
will have already set context.User using this scheme'sAuthenticateAsync()
Authenticate logic
AllowAnoynmous
was specified, authorization is skipped, and the filter logic short circuits and is done.IPolicyEvaluator.AuthenticateAsync(policy, authenticationResult, httpContext)
is called with the result from step 2. This just basically turns into a call toIAuthorizationService.AuthorizeAsync
, and the result is used to determine the appropriateChallenge/ForbidResult
if needed.Claims Transformation
Simpler, new
IClaimsTransformation
service with a single method:Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
We call this on any successful
AuthenticateAsync
call.How to replicate branched auth middleware functionality in 2.0
It turns out a massive amount of people are not using the
AuthenticationSchemes
property on theAuthorizeAttribute
and instead are using middleware branching to select the current scheme for a request based on some logic (most commonly a path prefix/api
).This will use the correct authentication scheme when doing auth for this specific controller.
As an alternative, here's a middleware that can be used to change the current user based on the authentication scheme.
Usage looks like this:
In Startup.ConfigureServices
In Startup.Configure
UPDATE: I should point out that if you're using this middleware and the user isn't authorized, the challenge/forbid issued will end up being the default scheme. If none is set, an exception will be thrown.
Known issues/breaking changes:
IOptionsMonitor
and named options, this introduces a breaking change for any apps that were configuring auth using a customIConfigureOptions
. These will need to be updated to implementIConfigureNamedOptions
instead, which just means adding an additional public get/set Name property.The text was updated successfully, but these errors were encountered: