J'ai une application Internet principale 2.0 et un problème d'autorisation. Je souhaite utiliser une autorisation personnalisée avec une authentification spéciale request.header et une authentification standart par défaut ..__ Tout d'abord, j'ajoute une configuration dans startup.cs:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
...
services.AddAuthorization(options =>
{
options.AddPolicy(DefaultAuthorizedPolicy, policy =>
{
policy.Requirements.Add(new TokenAuthRequirement());
});
});
services.AddSingleton<IAuthorizationHandler, AuthTokenPolicy>();
...
}
et AuthTokenPolicy.cs
public class AuthTokenPolicy : AuthorizationHandler<TokenAuthRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TokenAuthRequirement requirement)
{
var filterContext = context.Resource as AuthorizationFilterContext;
var response = filterContext.HttpContext.Response;
try
{
// some validation code
var isValidToken = isValidTokenTask.Result;
if (!isValidToken)
{
response.StatusCode = 401;
return Task.CompletedTask;
}
response.StatusCode = 200;
context.Succeed(requirement);
}
catch (Exception)
{
return Task.CompletedTask;
}
return Task.CompletedTask;
}
}
et dans HomeController.cs
[Authorize(Policy = Startup.DefaultAuthorizedPolicy)]
public async Task<IActionResult> IsVisible()
Si j'utilise un mauvais request.header dans AuthTokenPolicy, je le vois. Mais dans les journaux, je vois une erreur:
System.InvalidOperationException: Aucun authenticationScheme n'a été spécifié et aucun DefaultChallengeScheme n'a été trouvé.\R\n à Microsoft.AspNetCore.Authentication.AuthenticationService.d__11.MoveNext ()\r\n --- Fin de la trace de pile d'un emplacement précédent où exception a été jeté ---\r\n à System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw ()\r\n à System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (tâche) en Microsoft.AspNetCore.r. ChallengeResult.d__14.MoveNext ()\r\n --- Trace de fin de pile de l'emplacement précédent où une exception a été levée ---\r\n à System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw ()\r\n à System .Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (Tâche)\r\n à Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__19.MoveNext ()\r\n --- Fin de la trace de pile d'un emplacement précédent où une exception a été exécutée. ---\r\n à System.Runtime.ExceptionServices.ExceptionDispatchIn fo.Throw ()\r\n à System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (Task Task)\r\n à Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__17.MoveNext ()\r\n --- Trace de fin de pile de l’emplacement précédent où une exception a été levée ---\r\n à System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw ()\r\n à System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (tâche)\r\n à Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__15.MoveNext ()\r\n --- trace de fin de pile de l'emplacement précédent où une exception a été générée ---\r\n à System.Runtime.ExceptionServices. ExceptionDispatchInfo.Throw ()\r\n à System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (Tâche)\r\n à Microsoft.AspNetCore.Builder.RouterMiddleware.d__MovNext (\ r\n) trace de pile de l'emplacement précédent où une exception a été levée ---\r\n à System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw ( )\r\n à System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (Task task)\r à Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.d__3.MoveNext ()\r\n --- Fin de la trace de la précédente emplacement où une exception a été levée ---\r\n à System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw ()\r\n à System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (tâche à effectuer)\r\n à React.Asp .BabelFileMiddleware.d__5.MoveNext ()\r\n --- Trace de fin de pile de l'emplacement précédent où une exception a été levée ---\r\n à System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw ()\r\n à System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (Tâche de tâche)\r\n à Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.d__6.MoveNext ()\r\n --- Fin de la trace de pile d'un emplacement précédent où une exception a été créée - -\r\n à System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw ()\r\n à System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (tâche)\r\n à core.common.Middleware.LoggingMiddleware.d__3.MoveNext () dans D:\Dev\microservicePDP\Template\core\Commonware .cs: ligne 72
Après avoir lu Migration de l'authentification et de l'identité vers ASP.NET Core 2.0 j'ai ajouté ce code dans startup.cs
Citation de l'article:
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
});
Définissez un schéma par défaut dans 2.0 si l'une des conditions suivantes est remplie: Vous souhaitez que l'utilisateur soit automatiquement connecté Vous utilisez l'attribut [Autoriser] ou les règles d'autorisation sans spécifier de schéma
J'ai ajouté AuthenticationScheme et DefaultChallengeScheme dans ConfigureServices. Ce n'était pas une aide, la même erreur ici. J'ai essayé d'utiliser app.UseAuthentication (); Dans Configure dans StartUp.cs, aucun résultat ..___ Quelqu'un peut-il expliquer comment utiliser une autorisation personnalisée sans authentification?
Bien. La réponse correcte est: n'utilisez pas l'autorisation au lieu de l'authentification. Je devrais avoir un accès complet au service de tous les clients avec en-tête. Le code de travail est:
public class TokenAuthenticationHandler : AuthenticationHandler<TokenAuthenticationOptions>
{
public IServiceProvider ServiceProvider { get; set; }
public TokenAuthenticationHandler (IOptionsMonitor<TokenAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, IServiceProvider serviceProvider)
: base (options, logger, encoder, clock)
{
ServiceProvider = serviceProvider;
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync ()
{
var headers = Request.Headers;
var token = "X-Auth-Token".GetHeaderOrCookieValue (Request);
if (string.IsNullOrEmpty (token)) {
return Task.FromResult (AuthenticateResult.Fail ("Token is null"));
}
bool isValidToken = false; // check token here
if (!isValidToken) {
return Task.FromResult (AuthenticateResult.Fail ($"Balancer not authorize token : for token={token}"));
}
var claims = new [] { new Claim ("token", token) };
var identity = new ClaimsIdentity (claims, nameof (TokenAuthenticationHandler));
var ticket = new AuthenticationTicket (new ClaimsPrincipal (identity), this.Scheme.Name);
return Task.FromResult (AuthenticateResult.Success (ticket));
}
}
Startup.cs:
#region Authentication
services.AddAuthentication (o => {
o.DefaultScheme = SchemesNamesConst.TokenAuthenticationDefaultScheme;
})
.AddScheme<TokenAuthenticationOptions, TokenAuthenticationHandler> (SchemesNamesConst.TokenAuthenticationDefaultScheme, o => { });
#endregion
Et mycontroller.cs
[Authorize(AuthenticationSchemes = SchemesNamesConst.TokenAuthenticationDefaultScheme)]
public class MainController : BaseController
{ ...}
Je ne trouve pas TokenAuthenticationOptions maintenant, mais il était vide. J'ai trouvé la même classe PhoneNumberAuthenticationOptions:
namespace Project.Auth{
public class PhoneNumberAuthenticationOptions : AuthenticationSchemeOptions
{
public Regex PhoneMask { get; set; }// = new Regex("7\\d{10}");
}}
Vous devez définir la classe statique SchemesNamesConst Quelque chose comme:
namespace Common.Const{
public static class SchemesNamesConst
{
public const string SchemesNamesConst= "TokenAuthenticationScheme";
}}
Lorsque j’ai utilisé la stratégie avant de définir également le schéma d’authentification par défaut. J'avais modifié le DefaultPolicy
donc c'était légèrement différent. Cependant, la même chose devrait fonctionner pour ajouter une politique.
services.AddAuthorization(options =>
{
options.AddPolicy(DefaultAuthorizedPolicy, policy =>
{
policy.Requirements.Add(new TokenAuthRequirement());
policy.AuthenticationSchemes = new List<string>()
{
CookieAuthenticationDefaults.AuthenticationScheme
}
});
});
Prenez en compte le fait que, par défaut, la propriété AuthenticationSchemes
utilise une liste en lecture seule. Je pense qu'il serait préférable de mettre cela en œuvre plutôt que de lister.
cela a fonctionné pour moi
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme,
options =>
{
options.LoginPath = new PathString("/auth/login");
options.AccessDeniedPath = new PathString("/auth/denied");
});
Si vous faites cela sur Visual Studio avec un projet principal Asp.Net et que, tout à coup, votre application ne commence pas avec le type de message d'erreur indiqué ci-dessous, ce qui a fonctionné pour moi était de décocher "Activer le lien du navigateur"
erreur :
Conversion> [13:31:10 ERR] Connection id "0HLJ153E20LDJ", Request id "0HLJ153E20LDJ:00000003": An unhandled exception was thrown by the application.
Conversion> System.ObjectDisposedException: The response has been aborted due to an unhandled application exception. ---> System.FormatException: Invalid ETag name
Conversion> at Microsoft.Net.Http.Headers.EntityTagHeaderValue..ctor(StringSegment tag, Boolean isWeak)
Conversion> at Microsoft.Net.Http.Headers.EntityTagHeaderValue..ctor(StringSegment tag)
Conversion> at Microsoft.VisualStudio.Web.BrowserLink.BrowserLinkMiddleWareUtil.AddToETag(ResponseHeaders responseHeader, Int32 port)
Conversion> at Microsoft.VisualStudio.Web.BrowserLink.BrowserLinkMiddleware.<>c__DisplayClass7_0.<ExecuteWithFilter>b__0()
Conversion> at Microsoft.AspNetCore.Http.HttpResponse.<>c.<.cctor>b__30_0(Object callback)
Conversion> at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.FireOnStartingMayAwait(Stack`1 onStarting)
Conversion> --- End of inner exception stack trace ---
Conversion> at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ThrowResponseAbortedException()
Conversion> at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.InitializeResponseAsync(Int32 firstWriteByteCount)
Conversion> at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.WriteAsync(ReadOnlyMemory`1 data, CancellationToken cancellationToken)
Conversion> at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpResponseStream.WriteAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken)
Conversion> at System.IO.Stream.WriteAsync(Byte[] buffer, Int32 offset, Int32 count)
Conversion> at Microsoft.VisualStudio.Web.BrowserLink.ScriptInjectionFilterStream.<>c__DisplayClass37_0.<<CreateResponseHandler>b__0>d.MoveNext()
Conversion> --- End of stack trace from previous location where exception was thrown ---
Conversion> at Microsoft.VisualStudio.Web.BrowserLink.SocketReader.ReadBytesIntoResponseHandler(Int64 totalBytesToRead, ResponseHandler handler, CancellationToken cancellationToken)
Conversion> at Microsoft.VisualStudio.Web.BrowserLink.HttpSocketAdapter.ResponseReader.ReadBytesIntoResponse(Int64 bytesToRead)
Conversion> at Microsoft.VisualStudio.Web.BrowserLink.HttpSocketAdapter.ResponseReader.ReadChunkedContent()
Conversion> at Microsoft.VisualStudio.Web.BrowserLink.HttpSocketAdapter.ResponseReader.ReadResponse()
Conversion> at Microsoft.VisualStudio.Web.BrowserLink.DelayConnectingHttpSocketAdapter.Microsoft.VisualStudio.Web.BrowserLink.IHttpSocketAdapter.WaitForResponseComplete()
Conversion> at Microsoft.VisualStudio.Web.BrowserLink.ScriptInjectionFilterStream.WaitForFilterComplete()
Conversion> at Microsoft.VisualStudio.Web.BrowserLink.BrowserLinkMiddleware.ExecuteWithFilter(IHttpSocketAdapter injectScriptSocket, String requestId, HttpContext httpContext)
Conversion> at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Conversion> at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Conversion> at Microsoft.AspNetCore.Server.IISIntegration.IISMiddleware.Invoke(HttpContext httpContext)
Conversion> at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
Votre déclaration initiale dans la solution marquée n'est pas tout à fait vraie. Bien que votre nouvelle solution puisse atteindre votre objectif initial, il est toujours possible de contourner l’erreur initiale tout en préservant votre logique AuthorizationHandler --à condition que vous ayez des gestionnaires de schémas d’authentification de base en place, même s’ils sont fonctionnellement squelettes.
En termes généraux, les gestionnaires d’authentification et les schémas sont conçus pour établir + valider l’identité, ce qui les rend indispensables au fonctionnement des gestionnaires/stratégies d’autorisation, car ils supposent qu’une identité a déjà été établie.
ASP.NET Dev Haok résume ce qu'il y a de mieux ici: "Aujourd'hui, l'authentification ne connaît pas l'autorisation du tout, elle ne se préoccupe que de produire un système ClaimsPrincipal par schéma. L'autorisation doit être quelque peu consciente de l'authentification; donc, AuthenticationSchemes dans la stratégie est un mécanisme pour que vous associez la stratégie aux schémas utilisés pour générer le principal des revendications effectives pour autorisation (ou utilise simplement la valeur par défaut httpContext.User pour la demande, qui repose sur DefaultAuthenticateScheme). " https: // github. com/aspnet/Sécurité/problèmes/1469
Dans mon cas, la solution sur laquelle je travaille fournissait son propre concept implicite d'identité, nous n'avions donc pas besoin de schémas d'authentification/de gestionnaires, mais simplement de jetons d'en-tête pour l'autorisation. Ainsi, jusqu'à ce que nos concepts d'identité changent, nos gestionnaires d'autorisation de jeton d'en-tête qui appliquent les stratégies peuvent être liés à des squelettes de schéma un à un.
Tags sur les terminaux:
[Authorize(AuthenticationSchemes = "AuthenticatedUserSchemeName", Policy = "AuthorizedUserPolicyName")]
Startup.cs:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = "AuthenticatedUserSchemeName";
}).AddScheme<ValidTokenAuthenticationSchemeOptions, ValidTokenAuthenticationHandler>("AuthenticatedUserSchemeName", _ => { });
services.AddAuthorization(options =>
{
options.AddPolicy("AuthorizedUserPolicyName", policy =>
{
//policy.RequireClaim(ClaimTypes.Sid,"authToken");
policy.AddAuthenticationSchemes("AuthenticatedUserSchemeName");
policy.AddRequirements(new ValidTokenAuthorizationRequirement());
});
services.AddSingleton<IAuthorizationHandler, ValidTokenAuthorizationHandler>();
Le gestionnaire d'authentification vide et le gestionnaire d'autorisation sont appelés (la configuration est identique à celle des publications respectives de OP), mais le gestionnaire d'autorisation applique toujours nos règles d'autorisation.