1

我正在尝试在我的 ASP.Core 3.1.10 应用程序中使用重定向来实现单次注销。我使用了来自https://www.itfoxtec.com/identitysaml2的代码。注销 POST 请求结果为 303
(User.Identity.IsAuthenticated 变为 false),但下一个 GET 请求结果为 400,未发生重定向(未执行 LoggedOut、SingleLogout 方法)。你能帮忙解决这个问题吗?

这是一个失败的GET SAMLRequest

<saml2p:LogoutRequest xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="_40c55084-a748-42be-ba8f-c5bb70010109" Version="2.0" IssueInstant="2021-07-12T20:55:39.5289450Z" Destination="http://myserver:5000/auth/realms/mycompany/protocol/saml" NotOnOrAfter="2021-07-12T21:05:39.5289589Z"><saml2:Issuer>mycompany-dev</saml2:Issuer><saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">user1234</saml2:NameID><saml2p:SessionIndex>c8c8b602-34d0-4eb1-aed4-71ae7a06a4b5::0e88e5c4-ce48-44a4-916c-5587a7fdb636</saml2p:SessionIndex></saml2p:LogoutRequest>

SAML2 配置

 saml2Configuration.SignAuthnRequest = true;
        saml2Configuration.SigningCertificate = CertificateUtil.Load(AppEnvironment.MapToPhysicalFilePath(Configuration["Saml2:SigningCertificateFile"]), Configuration["Saml2:SigningCertificatePassword"]);

        saml2Configuration.AllowedAudienceUris.Add(saml2Configuration.Issuer);

        var entityDescriptor = new EntityDescriptor();
        entityDescriptor.ReadIdPSsoDescriptorFromFile(Configuration["Saml2:IdPMetadataFile"]);
        if (entityDescriptor.IdPSsoDescriptor != null)
        {
            saml2Configuration.AllowedIssuer = entityDescriptor.EntityId;
            saml2Configuration.SingleSignOnDestination = entityDescriptor.IdPSsoDescriptor.SingleSignOnServices.First().Location;
            if (AppEnvironment.IsDevelopment() || AppEnvironment.IsStaging()) // todo test
            {
                saml2Configuration.SingleLogoutDestination = entityDescriptor.IdPSsoDescriptor.SingleLogoutServices.First().Location;
            }
            saml2Configuration.SignatureValidationCertificates.AddRange(entityDescriptor.IdPSsoDescriptor.SigningCertificates);
        }
        else
        {
            throw new Exception("IdPSsoDescriptor not loaded from metadata.");
        }

AuthController 登录:

[Route("Login")]
    [HttpGet]
    public IActionResult Login(string returnUrl = null)
    {
        var binding = new Saml2RedirectBinding();
        binding.SetRelayStateQuery(new Dictionary<string, string> { { relayStateReturnUrlKey, returnUrl ?? Url.Content("~/") } });

        var assertionConsumerServiceUrl = new Uri(GetBaseUri(false, false), Url.Content("~/Auth/AssertionConsumerService"));

        return binding.Bind(new Saml2AuthnRequest(config)
        {
            //Subject = new Subject { NameID = new NameID { ID = "username" } },
            AssertionConsumerServiceUrl = Startup.AppEnvironment.IsDevelopment() ? assertionConsumerServiceUrl : null
        }).ToActionResult();
    }enter code here

断言消费者服务

 [Route("AssertionConsumerService")]
    [HttpPost]
    public async Task<IActionResult> AssertionConsumerService()
    {
        var binding = new Saml2PostBinding();
        var saml2AuthnResponse = new Saml2AuthnResponse(config);

        binding.ReadSamlResponse(Request.ToGenericHttpRequest(), saml2AuthnResponse);
        if (saml2AuthnResponse.Status != Saml2StatusCodes.Success)
        {
            throw new AuthenticationException($"SAML Response status: {saml2AuthnResponse.Status}");
        }
        binding.Unbind(Request.ToGenericHttpRequest(), saml2AuthnResponse);
        ClaimsTransform.InitUserService(_userService);
        await saml2AuthnResponse.CreateSession(HttpContext, new TimeSpan(24,0,0), true, claimsTransform: (claimsPrincipal) => ClaimsTransform.Transform(claimsPrincipal).Result);

        var relayStateQuery = binding.GetRelayStateQuery();
        var returnUrl = relayStateQuery.ContainsKey(relayStateReturnUrlKey) ? relayStateQuery[relayStateReturnUrlKey] : Url.Content("~/");
        return Redirect(returnUrl);
    }

注销

[HttpPost("Logout")]       
    public async Task<IActionResult> Logout()
    {
        if (!User.Identity.IsAuthenticated)
        {
            return Redirect(Url.Content("~/"));
        }

        var binding = new Saml2RedirectBinding();
        var saml2LogoutRequest = await new Saml2LogoutRequest(config, User).DeleteSession(HttpContext);
        return binding.Bind(saml2LogoutRequest).ToActionResult();
    } 

登出:

 [Route("LoggedOut")]       
    public IActionResult LoggedOut()
    {
        var binding = new Saml2PostBinding();
        binding.Unbind(Request.ToGenericHttpRequest(), new Saml2LogoutResponse(config));

        return Redirect(Url.Content("~/"));
    }

单次注销:

[Route("SingleLogout")]       
    public async Task<IActionResult> SingleLogout()
    {
        Saml2StatusCodes status;
        var requestBinding = new Saml2RedirectBinding();
        var logoutRequest = new Saml2LogoutRequest(config, User);
        try
        {
            requestBinding.Unbind(Request.ToGenericHttpRequest(), logoutRequest);
            status = Saml2StatusCodes.Success;
            await logoutRequest.DeleteSession(HttpContext);
        }
        catch (Exception exc)
        {               
            Debug.WriteLine("SingleLogout error: " + exc.ToString());
            status = Saml2StatusCodes.RequestDenied;
        }

        var responsebinding = new Saml2RedirectBinding();
        responsebinding.RelayState = requestBinding.RelayState;
        var saml2LogoutResponse = new Saml2LogoutResponse(config)
        {
            InResponseToAsString = logoutRequest.IdAsString, 
            Status = status,
        };
        return responsebinding.Bind(saml2LogoutResponse).ToActionResult();
    }
4

1 回答 1

0

也许这是一个cookie问题。当您在域之间进行重定向时,浏览器不会将 .NET auth cookie 发送到服务器。您可以通过跟踪 (Chrome F12) 浏览器中的调用来检查是否发送了 .NET 身份验证 cookie。

也许这可以帮助.NetCore 身份验证 cookie 在所有请求中不持久 [Inermittent issue]

于 2021-07-21T20:07:42.173 回答