5 votes

Pourquoi le cookie d'authentification ne fonctionne-t-il pas avec l'attribut [Authorize] ?

Nous essayons d'implémenter une authentification via les cookies dans notre application Blazor-WebAssembly.

Contrôleur : Définir l'Auth-Cookie :

[Route("[controller]")]
[ApiController]
public class AuthController : ControllerBase
{
    [HttpPost]
    public async Task<AdUser> Login(Credentials pCredentials)
    {
        // [...] credential check jere

            var lClaims = new List<Claim> {
                new Claim(ClaimTypes.Name, "SamAccountName"),
            };
            var lClaimsIdentity = new ClaimsIdentity(lClaims, CookieAuthenticationDefaults.AuthenticationScheme);

            // set cookie
            await HttpContext.SignInAsync(
            CookieAuthenticationDefaults.AuthenticationScheme,
            new ClaimsPrincipal(lClaimsIdentity),
            new AuthenticationProperties
            {
                IsPersistent = true,
                ExpiresUtc = DateTime.UtcNow.AddYears(1),
                RedirectUri = this.Request.Host.Value
            });

        // [...]
    }
}

Lorsque je regarde dans les outils de développement du navigateur Edge, je peux voir que le cookie est installé :

enter image description here

Maintenant, ce qui suit Controller a une action de recherche et doit avoir un accès restreint en ajoutant l'attribut [Authorize] :

[Route("[controller]")]
[ApiController]
public class ClientsController : ControllerBase
{
    [HttpGet("search")]
    [Authorize]
    public ActionResult<List<Shared.Client>> Search(string pText)
    {
        // [...] Code here

        return lResult;
    }
}

Quand je fais une requête HTTP /Clients?search=My Search Text au ClientsController, l'outil de développement de l'Edge me montre qu'une demande a été faite au /Account/Login . Je ne comprends pas bien, car le code de réponse est 200 mais aucun contrôleur de compte n'existe dans mon projet.

Pourquoi mon cookie d'authentification ne fonctionne-t-il pas avec le système d'authentification de l'UE ? [Authorize] attribut ?

enter image description here

Quelques détails supplémentaires sur mes configurations :

Startup.cs (côté serveur)

namespace BlazorWebAssemblyApp.Server
{
    public class Startup
    {
        /// [...]

        public void ConfigureServices(IServiceCollection services)
        {
            // [...]
            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(); // This line is required for the authentication cookie       
            // [...]
        }
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        // [...]

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();
            endpoints.MapControllers();
            endpoints.MapFallbackToFile("index.html");
        });
    }
}

8voto

poke Points 64398

Si vous constatez que l'utilisateur n'est pas reconnu lors d'une prochaine demande après s'être explicitement connecté avec le schéma d'authentification par cookie, cela montre que vous n'avez pas correctement configuré le middleware d'authentification. Comme selon la documentation vous ne devrez pas seulement ajouter les services d'authentification en utilisant services.AddAuthentication(…) mais vous devrez également configurer le middleware d'authentification pour qu'il s'exécute en tant que partie du pipeline de requête. Cela ressemble généralement à ceci :

app.UseRouting();

// add the call to `UseAuthentication`
app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

En ajoutant le UseAuthentication() dans l'intergiciel, vous ferez en sorte que le schéma d'authentification par défaut - qui est le schéma du cookie dans votre cas - lance une tentative d'authentification de l'utilisateur. Ainsi, s'il y a un cookie d'authentification dans la requête, il sera utilisé pour authentifier l'utilisateur, que vous souhaitiez accéder à une route autorisée ou non.

Une fois que l'intergiciel s'exécute, les actions protégées avec seulement l'option [Authorize] fonctionnera également puisque l'authentification du schéma de cookies a déjà eu lieu (puisqu'il s'agit du schéma par défaut).

Sinon, si l'intergiciel n'est pas invoqué par défaut, vous devrez vous assurer que le schéma d'authentification est toujours explicitement invoqué chaque fois que vous devez accéder aux informations sur l'utilisateur. C'est ce que [Authorize(AuthenticationSchemes = "scheme-name")] fait : Avant que le autorisation s'exécute, il tentera d'authentifier les schémas spécifiés. - Si vous utilisez le middleware d'authentification et que vous avez le bon schéma par défaut, vous pouvez sauter cette étape puisque le schéma sera authentifié par défaut.

Dans votre code original, sans l'exécution de l'authentification, cela vous donne également l'explication de la raison pour laquelle vous avez été redirigé : Puisque le schéma d'authentification n'a pas été exécuté pour authentifier l'utilisateur, il n'y avait pas d'utilisateur connecté (même si l'utilisateur avait un cookie). Ainsi, lorsque l'utilisateur était autorisé aucun utilisateur n'était présent et vous avez été redirigé vers la page de connexion.

Pourquoi y a-t-il une redirection vers /Account/Login ?

Le schéma d'authentification par cookie est celui qui permet de rediriger les utilisateurs vers la page de connexion lorsque l'authentification est requise (par exemple, par le biais de l'option [Authorize] ) mais l'utilisateur n'a pas encore de cookie d'authentification. Dans ce cas, l'authentification sera "contestée", ce qui, pour le schéma du cookie, signifie que l'utilisateur sera redirigé vers la page de connexion où il devra s'identifier.

Par défaut, la route vers la page de connexion est configurée pour être /Account/Login . Cette valeur par défaut est là pour correspondre au comportement par défaut lorsque vous utilisez ASP.NET Core Identity. Vous pouvez facilement configurer cette route pour qu'elle corresponde à votre page de connexion réelle en modifiant les paramètres suivants CookieAuthenticationOptions.LoginPath . Vous pouvez le faire par exemple avec le AddCookie() appeler :

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        options.LoginPath = "/Auth/Login"; // using the AuthController instead
    });

Maintenant, lorsque les utilisateurs sont mis au défi, ils seront redirigés vers votre AuthController.Login au lieu de l'endroit où ils doivent se connecter.

Notez que le schéma de cookie ajoutera un paramètre de requête ReturnUrl à l'action de connexion qui contient le chemin d'accès à la page à laquelle l'utilisateur a essayé d'accéder à l'origine. Par exemple, si l'utilisateur accède à votre action de recherche, il sera redirigé vers la page suivante /Auth/Login?ReturnUrl=%2FClients%2Fsearch . On s'attend donc à ce que vous acceptiez ce paramètre de route et que vous retourniez à cette route lorsque la connexion est terminée, par exemple :

[HttpPost]
public async Task<IActionResult> Login(Credentials pCredentials, string returnUrl)
{
    // do login

    return LocalRedirect(returnUrl);
}

Vous pouvez également modifier le nom du paramètre ReturnUrl à ce que vous voulez en changeant CookieAuthenticationOptions.ReturnUrlParameter .

1voto

Óscar López Points 328

Vous êtes redirigé vers la "page de connexion" ou returnURL parce que votre authentification ne fonctionne pas correctement et que vous obtenez "Unauthorized". ASP.Net Core vous redirige par défaut lorsque l'authentification échoue au lieu de renvoyer un code 401.

Assurez-vous que vous l'implémentez de la bonne manière, comme indiqué dans le document suivant https://docs.microsoft.com/es-es/aspnet/core/security/authentication/identity?view=aspnetcore-3.1&tabs=visual-studio .

N'oubliez pas d'ajouter les lignes suivantes à votre méthode Configure dans la classe Startup.cs pour ajouter le middleware d'authentification :

app.UseAuthentication();
app.UseAuthorization();

Vérifiez que vous l'avez fait dans le bon ordre (l'ordre est important, puisque vous vous authentifiez d'abord, puis votre rôle est vérifié).

Ils doivent également être placés entre le app.UseRouting() et le app.UseEndpoints() appels.

0voto

Simon Points 432

Je l'ai obtenu par moi-même, en utilisant [Authorize(AuthenticationSchemes = AuthSchemes)] pour mon action dans le contrôleur. Voici le code :

[Route("[controller]")]
[ApiController]
public class ClientsController : ControllerBase
{          
    private const string AuthSchemes = CookieAuthenticationDefaults.AuthenticationScheme;

    [HttpGet("search")]
    [Authorize(AuthenticationSchemes = AuthSchemes)]
    public ActionResult<List<Shared.Client>> Search(Shared.Client.SearchProperty pProperty, string pText)
    {
        // [...]
    }
}

Vous pouvez lire plus sur ce sujet ici : https://docs.microsoft.com/de-de/aspnet/core/security/authorization/limitingidentitybyscheme?view=aspnetcore-3.1

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X