【问题标题】:ASP .NET Core cookie authenticationASP .NET Core cookie 身份验证
【发布时间】:2020-03-09 17:51:19
【问题描述】:

我有一个 ASP.NET Web API 站点,它使用从另一个 ASP.NET Web 窗体站点生成的身份验证 cookie。
由于 ASP.NET Web API 站点和 ASP.NET Web 窗体站点都具有相同的“machineKey”和相同的“form auth cookie name”,因此它允许用户登录到“Web 窗体站点”然后提取数据来自“Web API 站点”而无需重新身份验证,因为“身份验证”cookie 将在站点之间传递。
所有这些都是在 web.config 中完成的,不需要任何特殊代码即可工作。

现在我们想创建一个 ASP NET Core Web API 站点并使用相同的身份验证 cookie。

我似乎找不到任何关于如何在 .NET Core 中执行此操作的好文章。
有很多关于如何使用我们没有的 ASP 身份的文章,也有很多关于 auth cookie 的文章,但没有解释如何从其他站点获取它...

这是我在 Web API 中的 web.config 部分:

  <system.web>
    <authentication>
      <forms name=".TESTAUTH" cookieless="AutoDetect" requireSSL="true" domain=".test.com" slidingExpiration="true" protection="All" timeout="600"
             enableCrossAppRedirects="true" />
    </authentication>

    <!-- This is used to share the auth cookie between web sites -->
    <machineKey validationKey="SOMEKEY"
                decryptionKey="SOMEOTHERKEY" validation="SHA1" decryption="AES" compatibilityMode="Framework20SP2" />
  </system.web>

编辑 A
我们正在使用“Framework20SP2”,这似乎使问题复杂化。
这是一些代码的链接,这些代码将根据“Framework20SP2”解密身份验证票
https://github.com/dazinator/AspNetCore.LegacyAuthCookieCompat

如果我使用上面的 NuGet,它会解密 .NET Core 站点中的身份验证 cookie,但我似乎无法弄清楚如何让它在 .NET Core DataProtectionProvider 中工作。

【问题讨论】:

  • 我是那个项目的所有者,你最终解决了吗? “弄清楚如何让它在 .NET Core DataProtectionProvider 中工作”是什么意思。 ?据我所知,您不能在 .net 核心中使用 DPAPI 来解密来自旧版 .net(例如 Framework20SP2)的 cookie 有效负载。
  • @Darrell 我确实让它工作了。我有一个生成登录 cookie 的 ASP.NET 3.5 网站和一个使用 cookie 的 ASP.NET Core 3.1 站点,它似乎可以很好地解密 cookie。
  • 是的,使用我壮观的包对吗? DPAPI(DataProtectionProvider)没有进入那个等式,它是别的东西,所以这让我感到困惑;-)...... aaaaanyway!很高兴一切顺利!
  • @Darrell 你是对的,因为我没有让它与 DataProtectionProvider 一起工作,而是使用了你出色的产品......

标签: asp.net asp.net-mvc asp.net-core asp.net-web-api


【解决方案1】:

您需要确认的第一件事是应用程序托管在同一域或该域的子域中。否则考虑使用像 Identity Server 4/Azure AD 这样的令牌/sso 服务来实现 SSO。

使用 Katana Cookie 身份验证中间件的 ASP.NET 4.x 应用可以配置为生成与 ASP.NET Core Cookie 身份验证中间件兼容的身份验证 cookie。将 Microsoft.Owin.Security.Interop 包安装到 ASP.NET 4.x 应用中使用 DataProtectionProvider ,它为身份验证 cookie 有效负载数据的加密和解密提供数据保护服务。

您现在可以删除 machineKey 配置,Katana cookie 中间件使用数据保护,它不依赖于机器密钥而是依赖于持久化的密钥环,您应该确保它使用持久化密钥存储,并且该密钥存储是可访问的并由每个应用程序使用。

更多细节和代码示例见下面的文章:

https://docs.microsoft.com/en-us/aspnet/core/security/cookie-sharing?view=aspnetcore-3.0

【讨论】:

  • 感谢您的链接。我之前看过那个链接,但它建议我编辑当前的 ASP.NET 站点,在我的例子中是 .NET 3.5 并且已经存在了 10 多年,因此不是编辑的选项。我仍在尝试将一些信息拼凑在一起。我将在上面的问题中添加更多信息。
  • An ASP.NET 4.x app must target .NET Framework 4.5.1 or later. Otherwise, the necessary NuGet packages fail to install. 如果项目不能被编辑,你不能在它和.net core app之间共享cookie,因为.net core app使用新的数据保护并且不依赖机器钥匙,
【解决方案2】:

虽然这可行,但我不能 100% 确定这是最好/正确的方法,但是
这是我创建的主要类。

public class FormsAuthCookieTicketFormat : ISecureDataFormat<AuthenticationTicket>
{

    private LegacyFormsAuthenticationTicketEncryptor _Encryptor;
    private Sha1HashProvider _HashProvider;

    public FormsAuthCookieTicketFormat(string decryptionKey, string validationKey)
    {
        byte[] decryptionKeyBytes = HexUtils.HexToBinary(decryptionKey);
        byte[] validationKeyBytes = HexUtils.HexToBinary(validationKey);

        _Encryptor = new LegacyFormsAuthenticationTicketEncryptor(decryptionKeyBytes, validationKeyBytes, ShaVersion.Sha1, CompatibilityMode.Framework20SP2);
        _HashProvider = new Sha1HashProvider(validationKeyBytes);
    }

    public string Protect(AuthenticationTicket data)
    {
        throw new NotImplementedException();
    }

    public string Protect(AuthenticationTicket data, string purpose)
    {
        throw new NotImplementedException();
    }

    public AuthenticationTicket Unprotect(string protectedText)
    {
        throw new NotImplementedException();
    }

    public AuthenticationTicket Unprotect(string protectedText, string purpose)
    {
        var ticket = _Encryptor.DecryptCookie(protectedText);


        var identity = new ClaimsIdentity("MyCookie");
        identity.AddClaim(new Claim(ClaimTypes.Name, ticket.Name));
        identity.AddClaim(new Claim(ClaimTypes.IsPersistent, ticket.IsPersistent.ToString()));
        identity.AddClaim(new Claim(ClaimTypes.Expired, ticket.Expired.ToString()));
        identity.AddClaim(new Claim(ClaimTypes.Expiration, ticket.Expiration.ToString()));
        identity.AddClaim(new Claim(ClaimTypes.CookiePath, ticket.CookiePath));
        identity.AddClaim(new Claim(ClaimTypes.Version, ticket.Version.ToString()));

        // Add some additional properties to the authentication ticket.
        var props = new AuthenticationProperties();
        props.ExpiresUtc = ticket.Expiration.ToUniversalTime();
        props.IsPersistent = ticket.IsPersistent;

        var principal = new ClaimsPrincipal(identity);


        var authTicket = new AuthenticationTicket(principal, props, CookieAuthenticationDefaults.AuthenticationScheme);
        return authTicket;
    }
}

这是 Startup.cs 文件

var formsCookieFormat = new FormsAuthCookieTicketFormat(decryptionKey, validationKey);

services
    .AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    })
    .AddCookie(options =>
    {
        options.Cookie.Name = ".TESTCOOKIE";
        options.Cookie.Domain = ".TESTDOMAIN";
        options.Cookie.Path = "/";
        options.Cookie.HttpOnly = false;
        options.Cookie.SameSite = SameSiteMode.None;
        options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
        options.AccessDeniedPath = "/Login/";
        options.LoginPath = "/Login/";
        options.ReturnUrlParameter = "returnurl";
        options.ExpireTimeSpan = TimeSpan.FromMinutes(20);
        options.TicketDataFormat = formsCookieFormat;
        options.SlidingExpiration = true;
    });

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-01-27
    • 1970-01-01
    • 1970-01-01
    • 2021-06-15
    • 2017-09-11
    • 2023-04-01
    • 2019-08-17
    • 1970-01-01
    相关资源
    最近更新 更多