.NET Core Identity Server 4 认证与 Identity 认证的区别

118

我正在尝试理解在ASP.NET Core中进行身份验证的正确方法。我查看了几个资源(大多已过时)。

有些人提供替代方案,建议使用基于云的解决方案,如Azure AD,或使用IdentityServer4并自己托管令牌服务器。

在旧版本的.Net中,其中一种更简单的身份验证形式是创建一个自定义Iprinciple,并在其中存储附加的身份验证用户数据。

public interface ICustomPrincipal : System.Security.Principal.IPrincipal
{
    string FirstName { get; set; }

    string LastName { get; set; }
}

public class CustomPrincipal : ICustomPrincipal
{
    public IIdentity Identity { get; private set; }

    public CustomPrincipal(string username)
    {
        this.Identity = new GenericIdentity(username);
    }

    public bool IsInRole(string role)
    {
        return Identity != null && Identity.IsAuthenticated && 
           !string.IsNullOrWhiteSpace(role) && Roles.IsUserInRole(Identity.Name, role);
    }

    public string FirstName { get; set; }

    public string LastName { get; set; }

    public string FullName { get { return FirstName + " " + LastName; } }
}

public class CustomPrincipalSerializedModel
{
    public int Id { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }
}

然后您将数据序列化为一个 cookie,并将其返回给客户端。

public void CreateAuthenticationTicket(string username) {     

    var authUser = Repository.Find(u => u.Username == username);  
    CustomPrincipalSerializedModel serializeModel = new CustomPrincipalSerializedModel();

    serializeModel.FirstName = authUser.FirstName;
    serializeModel.LastName = authUser.LastName;
    JavaScriptSerializer serializer = new JavaScriptSerializer();
    string userData = serializer.Serialize(serializeModel);

    FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
    1,username,DateTime.Now,DateTime.Now.AddHours(8),false,userData);
    string encTicket = FormsAuthentication.Encrypt(authTicket);
    HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
    Response.Cookies.Add(faCookie);
}

我的问题是:

  1. 如何进行类似于之前版本的 .Net 那样的身份验证,旧方式仍然有效还是有更新版本。

  2. 使用自己的令牌服务器与创建自定义原则有什么利弊?

  3. 在使用基于云的解决方案或单独的令牌服务器时,如何将其与当前应用程序集成,在我的应用程序中是否仍需要一个用户表以及如何关联这两个表?

  4. 由于有许多不同的解决方案,我如何创建企业应用程序,允许通过 Gmail/Facebook 进行登录,同时仍能扩展到其他 SSO。

  5. 这些技术的一些简单实现是什么?

这个问题太宽泛,而且高度基于个人观点。可能有太多的可能答案,或者好的答案对于这种格式来说太长了。请添加细节以缩小答案集或隔离可以在几段中回答的问题。许多好问题基于专家经验产生一定程度的意见,但是对于这个问题的答案往往几乎完全基于意见,而不是事实、参考或具体专业知识。 - Nkosi
@Nkosi 抱歉,短语是那样的。我澄清了一下,使其更具体。 - johnny 5
5个回答

180

TL;DR

IdentityServer提供OAuth 2.0/OpenId-Connect的令牌加密和验证服务。

ASP.NET Identity是ASP.NET中当前的身份管理策略。

如何进行类似于之前版本的.Net的身份验证,旧方式是否仍然有效或是否有更新版本。

我认为在ASP.NET Core中你可以实现旧的方式,但一般来说,那种策略已经被ASP.NET Identity所取代,并且在ASP.NET Core中ASP.NET Identity仍然存在。

https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity

ASP.NET Identity使用类似SQL Server的后备存储来保存用户信息,例如用户名、密码(哈希)、电子邮件、电话,并且可以轻松地扩展以保存FirstName、LastName或其他信息。因此,没有必要将用户信息加密到cookie中并在客户端和服务器之间传递。它支持用户声明、用户令牌、用户角色和外部登录等概念。以下是ASP.NET Identity中的实体:
- AspNetUsers - AspNetUserRoles - AspNetUserClaims - AspNetUserLogins(用于链接外部身份提供者,如Google、AAD) - AspNetUserTokens(用于存储用户积累的access_tokens和refresh_tokens等内容)
使用自己的令牌服务器和创建自定义原则有何优缺点?
一个令牌服务器是一个系统,它生成包含授权和/或身份验证信息的简单数据结构。授权通常采用名为access_token的令牌形式。这将是“进入房子的钥匙”,让您通过门口进入受保护资源的住所,通常是Web API。对于身份验证,id_token包含用户/人员的唯一标识符。虽然将此类标识符放入access_token中很常见,但现在有了专门的协议:OpenID-Connect
拥有自己的安全令牌服务(STS)的原因是通过加密来保护您的信息资产,并控制哪些客户端(应用程序)可以访问这些资源。此外,身份控件的标准现在存在于OpenID-Connect规范中。IdentityServer是OAuth 2.0授权服务器与OpenID-Connect身份验证服务器相结合的示例。
如果您只想在应用程序中使用用户表,则不需要进行上述任何操作。您无需使用令牌服务器,只需使用ASP.NET Identity即可。ASP.NET Identity将您的用户映射到服务器上的ClaimsIdentity对象-无需自定义IPrincipal类。
当使用基于云的解决方案或单独的令牌服务器时,您如何将其与当前应用程序集成?我是否仍然需要在我的应用程序中使用用户表,如何关联这两个内容?
请参阅以下教程以将单独的身份验证解决方案与应用程序集成: https://identityserver4.readthedocs.io/en/latest/quickstarts/0_overview.html https://auth0.com/docs/quickstart/webapp/aspnet-core 至少需要一个两列表格,将用户名映射到外部提供程序的用户标识符。这就是AspNetUserLogins表在ASP.NET Identity中所做的。但是,该表中的行取决于AspNetUsers中是否存在用户记录。
ASP.NET Identity支持像Google、Microsoft、Facebook、任何OpenID-Connect提供程序和Azure AD这样的外部提供程序。(Google和Microsoft已经实现了OpenID-Connect协议,因此您不需要使用它们的自定义集成包,例如像这个)。此外,ADFS在ASP.NET Core Identity上还不可用。
请参阅此文档以开始使用ASP.NET Identity中的外部提供程序:

https://learn.microsoft.com/en-us/aspnet/core/security/authentication/social/

由于有许多不同的解决方案,我该如何创建一个企业应用程序,以允许通过Gmail / Facebook登录,同时仍能扩展到其他SSO?

如上所述,ASP.NET身份验证已经可以实现此功能。创建一个“外部提供者”表并驱动外部登录过程非常容易。因此,当出现新的“SSO”时,只需添加一个新行,并填写属性,例如提供程序的URL、客户端ID和他们给您的秘钥。ASP.NET身份验证已经在Visual Studio模板中构建了UI,但是请参见Social Login以获得更酷的按钮。

摘要

如果您只需要具有密码登录功能和用户配置文件的用户表,则ASP.NET身份验证非常完美。无需涉及外部机构。但是,如果有许多应用程序需要访问许多API,则独立的身份验证和访问令牌验证机构是有意义的。IdentityServer是一个很好的选择,或者请参见openiddict-coreAuth0以获得云解决方案。

抱歉,如果这篇文章没有达到您的期望或者太基础了,请随意提出建议以便更好地满足您的需求。
补充说明:Cookie认证
要使用cookie进行最简单的身份验证,请按照以下步骤操作。但是,据我所知,不支持自定义声明原则。为了达到同样的效果,请利用ClaimPrincipal对象的Claims列表。
在Visual Studio 2015/2017中创建一个新的ASP.NET Core 1.1 Web应用程序,在对话框中选择“无身份验证”。然后添加包:
Microsoft.AspNetCore.Authentication.Cookies

Startup.csConfigure 方法中放置以下内容(在 app.UseMvc 之前):
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationScheme = "MyCookieMiddlewareInstance",
    LoginPath = new PathString("/Controller/Login/"),
    AutomaticAuthenticate = true,
    AutomaticChallenge = true
});

然后构建一个登录UI并将HTML表单发布到Action方法,如下所示:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(String username, String password, String returnUrl = null)
{
    ViewData["ReturnUrl"] = returnUrl;
    if (ModelState.IsValid)
    {
        // check user's password hash in database
        // retrieve user info

        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.Name, username),
            new Claim("FirstName", "Alice"),
            new Claim("LastName", "Smith")
        };

        var identity = new ClaimsIdentity(claims, "Password");

        var principal = new ClaimsPrincipal(identity);

        await HttpContext.Authentication.SignInAsync("MyCookieMiddlewareInstance", principal);

        return RedirectToLocal(returnUrl);
    }

    ModelState.AddModelError(String.Empty, "Invalid login attempt.");

    return View();
}

HttpContext.User对象应该包含您的自定义声明,并且可以在ClaimPrincipal的List集合中轻松检索。
希望这足够了,因为一个完整的解决方案/项目对于StackOverflow帖子来说似乎有些过多。

1
请展示一个在核心中实现身份验证的例子。 - johnny 5
2
ASP.NET Core文档展示了典型的例子:https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity。 - travis.js
对于ASP.NET身份验证,这个链接里有示例吗?还是说你所说的已经过时了?https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity - travis.js
更新您的答案以提供一种简单的身份验证方式。使用声明原则,不要使用链接。 - johnny 5
谢谢!那很完美。 - johnny 5
显示剩余5条评论

15

TL;DR

Author intended to provide a full guide on implementing IdentityServer4 but had to settle for sharing some tips instead due to length limitations on StackOverflow. Token server is beneficial for enterprise solutions while ASP Identity suffices for simple websites supporting external logins. OpenIdConnect (OIDC) should be used for authentication, not OAuth. The proper flow for an OIDC client and web API involves the client logging in and setting a token, followed by the web API consuming the OIDC client to verify the access token against IdentityServer. Running a migration generates SQL using the configured context rather than generating it from the dll internally. There are two syntaxes for Migrations.

dotnet ef migrations add InitialIdentityServerMigration -c ApplicationDbContext

Add-Migration InitialIdentityServerDbMigration -c ApplicationDbContext

我认为Migration之后的参数是名称,为什么需要名称我不确定,ApplicationDbContext是一个Code-First DbContext,你可以在其中创建。

迁移使用一些自动魔法从启动配置中查找连接字符串,我只是假设它使用了服务器资源管理器中的连接。

如果您有多个项目,请确保将拥有ApplicationDbContext的项目设置为启动项目。

实现授权和身份验证时涉及很多组件,希望本文对某些人有所帮助。完全理解身份验证的最简单方法是分析其示例以整合所有内容,并确保阅读文档。


add-migration后面的名称是与您所做的发布/更改相关的参考。相同的名称将用于添加迁移脚本Up和Down。 - Jay
@Jay 谢谢你的澄清。 - johnny 5
身份验证服务器的配置数据库上下文仍不如IdentityDbContext好用。创建自定义实现很麻烦。Identityserver 4似乎没有跟进.core更新发布新的更新。 - Jay

9

ASP.NET Identity - 这是一种内置的身份验证方式,无论是Bearer还是Basic Authentication,它都为我们提供了现成的代码来执行用户注册、登录、更改密码等操作。

现在假设我们有10个不同的应用程序,在所有这10个应用程序中进行相同的操作是不可行的,非常脆弱且行为不良。

为了解决这个问题,我们可以将身份验证和授权集中起来,这样无论发生任何变化,都不会影响我们的10个应用程序。

身份服务器可以提供您实现此功能的能力。我们可以创建一个简单的Web应用程序作为身份服务,它将验证您的用户并提供一些JWT访问令牌。


正是我所需要的。 - Qudus

2

我一直使用内置的ASP.NET身份验证(以前是Membership)进行授权/身份验证,最近我实现了Auth0 (https://auth0.com),我建议你也可以尝试这个。


Auth0的.NET Core示例非常快速和简单易实现,但要使用所有功能则需要相当多的工作。我已经实现了集成了许多功能的Auth0,并且它运行良好,但像所有这些东西一样,它需要一些工作和一些挫折感。 - Mark Redman
当我成功地完成一个身份验证时,我会发布一篇深入的答案。我过去的一周都在处理身份验证问题。但是没有什么像应该那样直截了当。 - johnny 5

0
社交登录在身份验证中并不难实现,但需要进行一些初始设置,有时在线文档中列出的步骤并不完全相同。通常,您可以在尝试为社交登录设置平台的开发人员部分找到帮助。身份验证是替换旧版 .net 框架中发现的旧成员功能的东西。我发现令人惊讶的是,边缘用例(例如将已经拥有的 jwt 令牌传递给 Web Api)在在线示例中甚至在 pluralsight 上都没有涵盖。我确信您不需要自己的令牌授权来完成此操作,但我还没有找到任何关于如何传递不涉及自托管服务器的 get 或 post 数据的示例。

也许您对这个链接感兴趣:http://docs.identityserver.io/en/release/quickstarts/7_javascript_client.html - Jay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接