EveCrystali / P10

1 stars 0 forks source link

logout is not working from Frontend status 404 #21

Closed EveCrystali closed 3 weeks ago

EveCrystali commented 3 weeks ago

Request = POST https://localhost:7000/auth/logout HTTP/2 application/x-www-form-urlencoded Response HttResponse = 200 OK

IsAuthenticated = false ??

{Method: POST, RequestUri: 'https://localhost:5000/auth/logout/', Version: 1.1, Content: , Headers: { traceparent: 00-511e7c383d06861aa64b0c3a4fbc88e2-812a131e1fe06417-00 }} {StatusCode: 404, ReasonPhrase: 'Not Found', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers: { Date: Mon, 30 Sep 2024 07:57:49 GMT Server: Kestrel Content-Length: 0 }, Trailing Headers: { }}

EveCrystali commented 3 weeks ago

Frontend:

info: Frontend.Controllers.AuthController[0]
      Service URL for Auth is https://localhost:5000/auth
Frontend.Controllers.AuthController: Information: Service URL for Auth is https://localhost:5000/auth
info: System.Net.Http.HttpClient.Default.LogicalHandler[100]
      Start processing HTTP request POST https://localhost:5000/auth/logout/
System.Net.Http.HttpClient.Default.LogicalHandler: Information: Start processing HTTP request POST https://localhost:5000/auth/logout/
info: System.Net.Http.HttpClient.Default.ClientHandler[100]
      Sending HTTP request POST https://localhost:5000/auth/logout/
System.Net.Http.HttpClient.Default.ClientHandler: Information: Sending HTTP request POST https://localhost:5000/auth/logout/
info: System.Net.Http.HttpClient.Default.ClientHandler[101]
      Received HTTP response headers after 39.5143ms - 404
System.Net.Http.HttpClient.Default.ClientHandler: Information: Received HTTP response headers after 39.5143ms - 404
info: System.Net.Http.HttpClient.Default.LogicalHandler[101]
      End processing HTTP request after 42.0732ms - 404
System.Net.Http.HttpClient.Default.LogicalHandler: Information: End processing HTTP request after 42.0732ms - 404

ApiGateway:

warn: Ocelot.DownstreamRouteFinder.Middleware.DownstreamRouteFinderMiddleware[0]
      requestId: 0HN714M334T6I:00000001, previousRequestId: No PreviousRequestId, message: 'DownstreamRouteFinderMiddleware setting pipeline errors. IDownstreamRouteFinder returned Error Code: UnableToFindDownstreamRouteError Message: Failed to match Route configuration for upstream path: /auth/logout/, verb: POST.'
Ocelot.DownstreamRouteFinder.Middleware.DownstreamRouteFinderMiddleware: Warning: requestId: 0HN714M334T6I:00000001, previousRequestId: No PreviousRequestId, message: 'DownstreamRouteFinderMiddleware setting pipeline errors. IDownstreamRouteFinder returned Error Code: UnableToFindDownstreamRouteError Message: Failed to match Route configuration for upstream path: /auth/logout/, verb: POST.'
warn: Ocelot.Responder.Middleware.ResponderMiddleware[0]
      requestId: 0HN714M334T6I:00000001, previousRequestId: No PreviousRequestId, message: 'Error Code: UnableToFindDownstreamRouteError Message: Failed to match Route configuration for upstream path: /auth/logout/, verb: POST. errors found in ResponderMiddleware. Setting error response for request path:/auth/logout/, request method: POST'
Ocelot.Responder.Middleware.ResponderMiddleware: Warning: requestId: 0HN714M334T6I:00000001, previousRequestId: No PreviousRequestId, message: 'Error Code: UnableToFindDownstreamRouteError Message: Failed to match Route configuration for upstream path: /auth/logout/, verb: POST. errors found in ResponderMiddleware. Setting error response for request path:/auth/logout/, request method: POST'
EveCrystali commented 3 weeks ago

let's try : https://chatgpt.com/share/66fad2f1-c49c-8010-93ed-4346ce8e1503

  1. Résumé du Problème Symptômes :

Lors de la tentative de déconnexion via le Frontend, vous obtenez une erreur 404. En utilisant Postman pour envoyer une requête POST à https://localhost:5000/auth/logout, vous recevez une réponse 401 Unauthorized. La déconnexion fonctionne correctement lorsque vous accédez directement au microservice Auth (https://localhost:7201/auth/logout). Les logs du Frontend indiquent que le cookie P10AuthCookie n'est pas trouvé. Aucun log n'est généré du côté du microservice Auth lors de la tentative de déconnexion via Ocelot. Cause Probable :

Problème de Domaine des Cookies : Le cookie P10AuthCookie est défini pour le domaine d'Ocelot (localhost:5000), et le Frontend fonctionne sur localhost:7000. Par conséquent, le Frontend ne peut pas accéder directement à ce cookie, empêchant ainsi l'authentification de la requête de déconnexion via Ocelot.

  1. Comprendre les Limites des Cookies sur localhost Les navigateurs traitent localhost avec des ports différents comme des origines distinctes. Cela signifie que les cookies définis pour https://localhost:5000 ne sont pas accessibles depuis https://localhost:7000 et vice versa. Cela entraîne l'impossibilité pour le Frontend de lire ou d'envoyer le cookie P10AuthCookie lorsqu'il interagit directement avec Ocelot.

  2. Solution Proposée : Gérer la Déconnexion Directement via le Navigateur Pour contourner ce problème, nous devons permettre au navigateur de gérer directement la requête de déconnexion vers Ocelot. Cela garantit que le cookie P10AuthCookie est correctement envoyé avec la requête, permettant ainsi à Ocelot d'authentifier et de traiter la demande de déconnexion.

Étapes à Suivre : Supprimer la Méthode Logout dans le Frontend AuthController

Étant donné que le Frontend ne peut pas accéder au cookie P10AuthCookie, il est préférable de supprimer ou de désactiver la méthode Logout dans le Frontend AuthController. Cela évite des tentatives de déconnexion infructueuses via le serveur Frontend.

Action :

Dans Frontend>Controllers>AuthController.cs, commentez ou supprimez la méthode Logout :

// [HttpPost("logout")]
// [ValidateAntiForgeryToken]
// public async Task<IActionResult> Logout()
// {
//     // Logique de déconnexion
// }

Modifier la Vue _LoginPartial.cshtml pour Soumettre la Déconnexion Directement à Ocelot

Au lieu d'envoyer la requête de déconnexion via le Frontend AuthController, configurez le formulaire de déconnexion pour qu'il soumette directement la requête au point de terminaison de déconnexion d'Ocelot (https://localhost:5000/auth/logout). De cette manière, le navigateur envoie automatiquement le cookie P10AuthCookie avec la requête.

Action :

Dans Frontend>Views>Shared>_LoginPartial.cshtml, modifiez le formulaire de déconnexion comme suit :

<ul class="navbar-nav">
    <li class="nav-item" id="login-item" style="display: true;">
        <a class="nav-link" asp-controller="auth" asp-action="login">Connexion</a>
    </li>

    <li class="nav-item" id="logout-item" style="display: false;">
        <form class="form-inline" method="post" action="https://localhost:5000/auth/logout">
            @* Supprimer ou commenter le jeton antiforgery *@
            @* <input type="hidden" name="__RequestVerificationToken" value="@Antiforgery.GetTokens(Context).RequestToken" /> *@
            <button type="submit" class="nav-link btn btn-link">Se déconnecter</button>
        </form>
    </li>

    <li class="nav-item" id="user-name-item" style="display: none;">
        <span class="nav-link" id="user-name"></span>
    </li>
</ul>

Remarque : Puisque le Frontend ne peut pas gérer le cookie P10AuthCookie, il est préférable de retirer le jeton antiforgery pour cette requête spécifique.

Adapter le Contrôleur Auth dans le Microservice Auth pour Rediriger Après Déconnexion

Modifiez la méthode Logout dans le microservice Auth pour rediriger l'utilisateur vers la page d'accueil du Frontend après une déconnexion réussie.

Action :

Dans Auth>Controllers>AuthController.cs, ajustez la méthode Logout comme suit :

[HttpPost("logout")]
// [ValidateAntiForgeryToken] // Retirez ou commentez cet attribut si nécessaire
public async Task<IActionResult> Logout()
{
    await _signInManager.SignOutAsync();
    return Redirect("https://localhost:7000"); // Redirige vers la page d'accueil du Frontend
}

Vérifier et Mettre à Jour la Configuration d'Ocelot

Assurez-vous que la route /auth/logout est correctement configurée dans ocelot.json pour accepter les requêtes POST et qu'elle ne nécessite pas de validation antiforgery si elle est désactivée dans la vue.

Action :

Dans ApiGateway>ocelot.json, assurez-vous que la configuration pour /auth/logout est la suivante :

{
  "Routes": [
    {
      "DownstreamPathTemplate": "/auth/logout",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 7201
        }
      ],
      "UpstreamPathTemplate": "/auth/logout",
      "UpstreamHttpMethod": ["POST"],
      "RouteIsCaseSensitive": false,
      "AuthenticationOptions": {
        "AuthenticationProviderKey": "P10AuthCookie",
        "AllowedScopes": []
      },
      "RateLimitOptions": {
        "EnableRateLimiting": false
      },
      "CorsPolicy": {
        "AllowAnyOrigin": false,
        "AllowCredentials": true,
        "AllowedOrigins": ["https://localhost:7000"], 
        "AllowedMethods": ["POST"],
        "AllowedHeaders": ["*"]
      }
    },
    // Autres routes...
  ],
  "GlobalConfiguration": {
    "BaseUrl": "https://localhost:5000"
  }
}

Assurez-vous que :

Les routes spécifiques (comme /auth/logout) sont définies avant les routes génériques pour éviter les conflits de routage. L'AuthenticationProviderKey correspond bien à celui configuré dans Ocelot ("P10AuthCookie"). Les politiques CORS sont correctement définies pour permettre les requêtes depuis le Frontend (https://localhost:7000). Redémarrer les Services et Tester

Après avoir effectué les modifications, redémarrez tous les services (Ocelot, Frontend, Auth) pour appliquer les nouvelles configurations.

Action :

Redémarrez Ocelot : Assurez-vous que les nouvelles routes sont chargées. Redémarrez le Frontend et le Microservice Auth : Pour appliquer les modifications de code. Tester la Déconnexion

Effectuez les tests suivants pour vérifier que la déconnexion fonctionne comme prévu :

Connexion : Connectez-vous via le Frontend (https://localhost:7000) et assurez-vous que le cookie P10AuthCookie est défini pour le domaine localhost:5000.

Déconnexion : Cliquez sur le bouton de déconnexion. Le formulaire devrait soumettre une requête POST directement à https://localhost:5000/auth/logout, envoyant ainsi le cookie P10AuthCookie.

Redirection : Après une déconnexion réussie, vous devriez être redirigé automatiquement vers la page d'accueil du Frontend (https://localhost:7000).

Vérification des Logs : Consultez les logs d'Ocelot et du microservice Auth pour vous assurer que la requête de déconnexion est bien reçue et traitée.

Vérification des Cookies : Utilisez les outils de développement de votre navigateur (F12) pour vérifier que le cookie P10AuthCookie est supprimé après la déconnexion.

  1. Points Clés et Conseils Gestion des Cookies : Les cookies sont sensibles au domaine et au chemin. Assurez-vous que le cookie P10AuthCookie est défini pour le domaine localhost:5000 et que le Frontend peut envoyer des requêtes à ce domaine pour inclure le cookie.

CORS Configuration : La configuration CORS dans Ocelot doit permettre les requêtes depuis le Frontend (https://localhost:7000) avec les méthodes HTTP appropriées et les en-têtes nécessaires.

Ordre des Routes dans Ocelot : Les routes spécifiques doivent toujours être définies avant les routes génériques dans ocelot.json pour éviter que les requêtes spécifiques ne soient capturées par des routes génériques.

Antiforgery Tokens : Si vous désactivez la validation des jetons antiforgery pour la déconnexion, assurez-vous que cette action ne présente pas de risque de sécurité. Dans ce contexte, où la déconnexion est une action simple, cela peut être acceptable, mais soyez conscient des implications.

  1. Exemple Complet de Code Modifié Frontend>Views>Shared>_LoginPartial.cshtml :
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Antiforgery

<ul class="navbar-nav">
    <li class="nav-item" id="login-item" style="display: true;">
        <a class="nav-link" asp-controller="auth" asp-action="login">Connexion</a>
    </li>

    <li class="nav-item" id="logout-item" style="display: false;">
        <form class="form-inline" method="post" action="https://localhost:5000/auth/logout">
            @* Supprimer le jeton antiforgery *@
            @* <input type="hidden" name="__RequestVerificationToken" value="@Antiforgery.GetTokens(Context).RequestToken" /> *@
            <button type="submit" class="nav-link btn btn-link">Se déconnecter</button>
        </form>
    </li>

    <li class="nav-item" id="user-name-item" style="display: none;">
        <span class="nav-link" id="user-name"></span>
    </li>
</ul>

<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
    $(document).ready(function () {
        console.log("Starting to fetch user data from /status");
        $.ajax({
            url: window.location.protocol + '//' + window.location.host + '/auth/status', 
            method: "GET",
            success: function (data) {
                console.log("Received user data from /status", data);

                // Vérifie le type des données reçues pour s'assurer qu'il s'agit bien d'un objet
                console.log("Type of isAuthenticated:", typeof data.isAuthenticated);
                console.log("Type of username:", typeof data.username);

                // Assure-toi que `isAuthenticated` est un booléen et non un tableau vide
                const isAuthenticated = Array.isArray(data.isAuthenticated) ? false : data.isAuthenticated;
                const username = Array.isArray(data.username) ? "Utilisateur inconnu" : data.username;

                if (isAuthenticated) {
                    console.log("User is authenticated, showing logout item and user name item");
                    $("#logout-item").show();
                    $("#user-name-item").show();
                    $("#user-name").text(username || "Utilisateur");
                    $("#login-item").hide();
                } else {
                    console.log("User is not authenticated, showing login item");
                    $("#login-item").show();
                    $("#logout-item").hide();
                    $("#user-name-item").hide();
                }
            },
            error: function (err) {
                console.log("Error fetching user data from /status", err);
                $("#login-item").show();
            }
        });
    });
</script>

Auth>Controllers>AuthController.cs :

using Auth.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;

namespace Auth.Controllers;

[Route("auth")]
[ApiController]
public class AuthController : ControllerBase
{
    private readonly UserManager<IdentityUser> _userManager;
    private readonly SignInManager<IdentityUser> _signInManager;
    private readonly ILogger<AuthController> _logger;

    public AuthController(UserManager<IdentityUser> userManager,
                          SignInManager<IdentityUser> signInManager,
                          ILogger<AuthController> logger)
    {
        _userManager = userManager;
        _signInManager = signInManager;
        _logger = logger;
    }

    [HttpPost("logout")]
    // [ValidateAntiForgeryToken] // Retirez ou commentez cet attribut si nécessaire
    public async Task<IActionResult> Logout()
    {
        await _signInManager.SignOutAsync();
        return Redirect("https://localhost:7000"); // Redirige vers la page d'accueil du Frontend
    }

    // Autres méthodes (login, register, status)...
}

ApiGateway>Ocelot.json :

Assurez-vous que les routes spécifiques sont placées avant les routes génériques et que la configuration CORS est correcte.

{
  "Routes": [
    {
      "DownstreamPathTemplate": "/auth/logout",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 7201
        }
      ],
      "UpstreamPathTemplate": "/auth/logout",
      "UpstreamHttpMethod": ["POST"],
      "RouteIsCaseSensitive": false,
      "AuthenticationOptions": {
        "AuthenticationProviderKey": "P10AuthCookie",
        "AllowedScopes": []
      },
      "RateLimitOptions": {
        "EnableRateLimiting": false
      },
      "CorsPolicy": {
        "AllowAnyOrigin": false,
        "AllowCredentials": true,
        "AllowedOrigins": ["https://localhost:7000"], 
        "AllowedMethods": ["POST"],
        "AllowedHeaders": ["*"]
      }
    },
    {
      "DownstreamPathTemplate": "/auth/login",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 7201
        }
      ],
      "UpstreamPathTemplate": "/auth/login",
      "UpstreamHttpMethod": ["POST"],
      "RouteIsCaseSensitive": false,
      "AuthenticationOptions": null,
      "RateLimitOptions": {
        "EnableRateLimiting": false
      },
      "CorsPolicy": {
        "AllowAnyOrigin": false,
        "AllowCredentials": true,
        "AllowedOrigins": ["https://localhost:7000"],
        "AllowedMethods": ["GET", "POST", "OPTIONS"],
        "AllowedHeaders": ["*"]
      }
    },
    {
      "DownstreamPathTemplate": "/auth/status",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 7201
        }
      ],
      "UpstreamPathTemplate": "/auth/status",
      "UpstreamHttpMethod": ["GET"],
      "RouteIsCaseSensitive": false,
      "AuthenticationOptions": null,
      "RateLimitOptions": {
        "EnableRateLimiting": false
      },
      "CorsPolicy": {
        "AllowAnyOrigin": false,
        "AllowCredentials": true,
        "AllowedOrigins": ["https://localhost:7000"],
        "AllowedMethods": ["GET"],
        "AllowedHeaders": ["*"]
      }
    },
    // Ajoutez la route pour le Frontend si nécessaire
    // {
    //   "DownstreamPathTemplate": "/{everything}",
    //   "DownstreamScheme": "https",
    //   "DownstreamHostAndPorts": [
    //     { "Host": "localhost", "Port": 7000 }
    //   ],
    //   "UpstreamPathTemplate": "/frontend/{everything}",
    //   "UpstreamHttpMethod": ["GET", "POST", "PUT", "DELETE"]
    // },
    {
      "UpstreamPathTemplate": "/",
      "DownstreamPathTemplate": "/",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 7200
        }
      ]
    }
  ],
  "GlobalConfiguration": {
    "BaseUrl": "https://localhost:5000"
  }
}
  1. Vérifications Finales Cookies dans le Navigateur : Après une connexion réussie, vérifiez que le cookie P10AuthCookie est bien défini pour le domaine localhost:5000. Utilisez les outils de développement de votre navigateur (F12) pour inspecter les cookies.

Requêtes de Déconnexion : Assurez-vous que lorsque vous soumettez le formulaire de déconnexion, la requête POST est envoyée directement à https://localhost:5000/auth/logout et que le cookie P10AuthCookie est inclus dans cette requête.

Logs Ocelot et Auth : Consultez les logs d'Ocelot et du microservice Auth pour vous assurer que la requête de déconnexion est bien reçue et traitée sans erreurs.

Redirection : Après la déconnexion, l'utilisateur doit être redirigé vers la page d'accueil (https://localhost:7000).

  1. Alternative : Utiliser JWT Tokens au Lieu des Cookies Si malgré ces ajustements le problème persiste, envisagez de passer à une authentification basée sur des tokens JWT. Les JWT peuvent être stockés côté client (par exemple, dans le localStorage ou les cookies avec les attributs appropriés) et envoyés dans les en-têtes Authorization avec chaque requête, ce qui simplifie la gestion des authentifications dans une architecture en microservices.

  2. Conclusion Le problème principal était lié à l'inaccessibilité du cookie P10AuthCookie par le Frontend en raison des différences de domaines (localhost:5000 vs localhost:7000). En modifiant le processus de déconnexion pour que le navigateur envoie directement la requête à Ocelot, vous permettez à Ocelot d'accéder au cookie nécessaire pour authentifier et traiter la demande de déconnexion. Cette approche garantit que la déconnexion fonctionne correctement et que l'utilisateur est redirigé vers la page d'accueil sans rencontrer d'erreurs.

Si, après avoir suivi ces étapes, vous rencontrez toujours des problèmes, veuillez fournir les nouvelles logs d'Ocelot et du microservice Auth pour une analyse plus approfondie.

Bon courage et n'hésitez pas à revenir pour toute assistance supplémentaire !