结合使用.NET Core Identity和API [英] Use .NET Core Identity with an API

查看:58
本文介绍了结合使用.NET Core Identity和API的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经创建了一个API并通过相同的API设置了JWT身份验证(我选择不使用IdentityServer4).

i've created an API and set up JWT auth from the same API (I chose not to use IdentityServer4).

我是通过 services.AddAuthentication

然后我在控制器中创建了令牌,并且可以正常工作.

And then I created tokens in the controller and it works.

但是我现在想添加注册等.但是我不希望自己编写代码以散列密码,处理注册电子邮件等.

However I now want to add registration etc. But i prefer not to write my own code for hashing passwords, handling registration emails etc.

所以我遇到了ASP.NET Core Identity,这看起来像我所需要的,除了它添加了一些我不需要的UI东西(因为它只是一个API和我想要完全独立的UI).

So I came across ASP.NET Core Identity and it seems like what I need, except from that it adds some UI stuff that I dont need (because its just an API and the UI i want completely independent).

但是在MSDN上这样写:

But on MSDN is written:

ASP.NET Core Identity将用户界面(UI)登录功能添加到ASP.NET Core Web应用程序.要保护Web API和SPA,请使用以下一种以下:

ASP.NET Core Identity adds user interface (UI) login functionality to ASP.NET Core web apps. To secure web APIs and SPAs, use one of the following:

Azure Active Directory

Azure Active Directory

Azure Active Directory B2C(Azure AD B2C)

Azure Active Directory B2C (Azure AD B2C)

IdentityServer4

IdentityServer4

那么仅将Core Identity用于API的哈希和注册逻辑真的不是一个好主意吗?不能让我忽略UI功能吗?这非常令人困惑,因为我不想使用IdentityServer4或创建自己的用户管理逻辑.

So is it really a bad idea to use Core Identity just for hashing and registration logic for an API? Cant I just ignore the UI functionality? It's very confusing because I'd rather not use IdentityServer4 or create my own user management logic.

推荐答案

让我说说捆绑身份与UI,Cookie以及添加了此或该内容的各种扩展方法的混淆,但不要这样做.至少在构建不需要cookie或UI的现代Web API时添加这个或那个很烦人.

Let me just get off my chest that the bundling Identity does with the UI, the cookies and the confusing various extension methods that add this or that, but don't add this or that, is pretty annoying, at least when you build modern web APIs that need no cookies nor UI.

在某些项目中,我还使用带有身份的手动JWT令牌生成功能来实现成员资格功能和用户/密码管理.

In some projects I also use manual JWT token generation with Identity for the membership features and user/password management.

基本上,最简单的方法是检查源代码.

Basically the simplest thing to do is to check the source code.

  1. AddDefaultIdentity()添加身份验证,添加Identity cookie,添加UI,并调用 AddIdentityCore();但不支持角色:
  1. AddDefaultIdentity() adds authentication, adds the Identity cookies, adds the UI, and calls AddIdentityCore(); but has no support for roles:

public static IdentityBuilder AddDefaultIdentity<TUser>(this IServiceCollection services, Action<IdentityOptions> configureOptions) where TUser : class
{
    services.AddAuthentication(o =>
    {
        o.DefaultScheme = IdentityConstants.ApplicationScheme;
        o.DefaultSignInScheme = IdentityConstants.ExternalScheme;
    })
    .AddIdentityCookies(o => { });

    return services.AddIdentityCore<TUser>(o =>
    {
        o.Stores.MaxLengthForKeys = 128;
        configureOptions?.Invoke(o);
    })
        .AddDefaultUI()
        .AddDefaultTokenProviders();
}

  1. AddIdentityCore()是一个简化后的版本,它仅添加基本服务,但甚至不添加身份验证,也不支持角色(在这里您已经可以看到什么是单独的服务)添加,以根据需要更改/覆盖/删除它们):
  1. AddIdentityCore() is a more stripped down version that only adds basic services, but it doesn't even add authentication, and also no support for roles (here you can already see what individual services are added, to change/override/remove them if you want):


public static IdentityBuilder AddIdentityCore<TUser>(this IServiceCollection services, Action<IdentityOptions> setupAction)
    where TUser : class
{
    // Services identity depends on
    services.AddOptions().AddLogging();

    // Services used by identity
    services.TryAddScoped<IUserValidator<TUser>, UserValidator<TUser>>();
    services.TryAddScoped<IPasswordValidator<TUser>, PasswordValidator<TUser>>();
    services.TryAddScoped<IPasswordHasher<TUser>, PasswordHasher<TUser>>();
    services.TryAddScoped<ILookupNormalizer, UpperInvariantLookupNormalizer>();
    services.TryAddScoped<IUserConfirmation<TUser>, DefaultUserConfirmation<TUser>>();
    // No interface for the error describer so we can add errors without rev'ing the interface
    services.TryAddScoped<IdentityErrorDescriber>();
    services.TryAddScoped<IUserClaimsPrincipalFactory<TUser>, UserClaimsPrincipalFactory<TUser>>();
    services.TryAddScoped<UserManager<TUser>>();

    if (setupAction != null)
    {
        services.Configure(setupAction);
    }

    return new IdentityBuilder(typeof(TUser), services);
}

现在到目前为止,这种感觉是正确的,对吧?

Now that kind of makes sense so far, right?

  1. 但是输入 AddIdentity(),它似乎是最肿的,是唯一直接支持角色的人,但令人困惑的是它似乎并没有添加UI:
  1. But enter AddIdentity(), which appears to be the most bloated, the only one that supports roles directly, but confusingly enough it doesn't seem to add the UI:

public static IdentityBuilder AddIdentity<TUser, TRole>(
    this IServiceCollection services,
    Action<IdentityOptions> setupAction)
    where TUser : class
    where TRole : class
{
    // Services used by identity
    services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
        options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
        options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
    })
    .AddCookie(IdentityConstants.ApplicationScheme, o =>
    {
        o.LoginPath = new PathString("/Account/Login");
        o.Events = new CookieAuthenticationEvents
        {
            OnValidatePrincipal = SecurityStampValidator.ValidatePrincipalAsync
        };
    })
    .AddCookie(IdentityConstants.ExternalScheme, o =>
    {
        o.Cookie.Name = IdentityConstants.ExternalScheme;
        o.ExpireTimeSpan = TimeSpan.FromMinutes(5);
    })
    .AddCookie(IdentityConstants.TwoFactorRememberMeScheme, o =>
    {
        o.Cookie.Name = IdentityConstants.TwoFactorRememberMeScheme;
        o.Events = new CookieAuthenticationEvents
        {
            OnValidatePrincipal = SecurityStampValidator.ValidateAsync<ITwoFactorSecurityStampValidator>
        };
    })
    .AddCookie(IdentityConstants.TwoFactorUserIdScheme, o =>
    {
        o.Cookie.Name = IdentityConstants.TwoFactorUserIdScheme;
        o.ExpireTimeSpan = TimeSpan.FromMinutes(5);
    });

    // Hosting doesn't add IHttpContextAccessor by default
    services.AddHttpContextAccessor();
    // Identity services
    services.TryAddScoped<IUserValidator<TUser>, UserValidator<TUser>>();
    services.TryAddScoped<IPasswordValidator<TUser>, PasswordValidator<TUser>>();
    services.TryAddScoped<IPasswordHasher<TUser>, PasswordHasher<TUser>>();
    services.TryAddScoped<ILookupNormalizer, UpperInvariantLookupNormalizer>();
    services.TryAddScoped<IRoleValidator<TRole>, RoleValidator<TRole>>();
    // No interface for the error describer so we can add errors without rev'ing the interface
    services.TryAddScoped<IdentityErrorDescriber>();
    services.TryAddScoped<ISecurityStampValidator, SecurityStampValidator<TUser>>();
    services.TryAddScoped<ITwoFactorSecurityStampValidator, TwoFactorSecurityStampValidator<TUser>>();
    services.TryAddScoped<IUserClaimsPrincipalFactory<TUser>, UserClaimsPrincipalFactory<TUser, TRole>>();
    services.TryAddScoped<IUserConfirmation<TUser>, DefaultUserConfirmation<TUser>>();
    services.TryAddScoped<UserManager<TUser>>();
    services.TryAddScoped<SignInManager<TUser>>();
    services.TryAddScoped<RoleManager<TRole>>();

    if (setupAction != null)
    {
        services.Configure(setupAction);
    }

    return new IdentityBuilder(typeof(TUser), typeof(TRole), services);
}

您可能需要的全部是 AddIdentityCore(),此外,您还必须自己使用 AddAuthentication().

All in all what you probably need is the AddIdentityCore(), plus you have to use AddAuthentication() on your own.

此外,如果您使用 AddIdentity(),请务必在调用 AddIdentity()之后运行 AddAuthentication()配置,因为您必须覆盖默认的身份验证方案(我遇到了与此相关的问题,但忘记了详细信息).

Also, if you use AddIdentity(), be sure to run your AddAuthentication() configuration after calling AddIdentity(), because you have to override the default authentication schemes (I ran into problems related to this, but can't remember the details).

(另一个可能使阅读本书的人感兴趣的信息是 SignInManager.PasswordSignInAsync() SignInManager.CheckPasswordSignInAsync() UserManager之间的区别.CheckPasswordAsync().这些都是您可以找到并出于授权目的而调用的所有公共方法. PasswordSignInAsync()实现两步登录(还设置cookie;可能仅在使用时AddIdentity() AddDefaultIdentity())并调用 CheckPasswordSignInAsync(),这实现了用户锁定处理并调用了 UserManager.CheckPasswordAsync(),它只是检查密码,因此,要获得正确的身份验证,最好不要直接调用 UserManager.CheckPasswordAsync(),而是通过 CheckPasswordSignInAsync()进行.,在单因素JWT令牌方案中,可能不需要调用 PasswordSignInAsync()(您可以运行重定向问题).如果您在启动中包含了设置了正确的JwtBearer令牌方案的 UseAuthentication()/AddAuthentication(),则客户端下次发送带有有效令牌的请求时,身份验证中间件将启动,客户端将被登录";即任何有效的JWT令牌都将允许客户端访问受[Authorize]保护的控制器操作.)

(Another tidbit of information that might be interesting for people reading this is the distinction between SignInManager.PasswordSignInAsync(), SignInManager.CheckPasswordSignInAsync() and UserManager.CheckPasswordAsync(). These are all public methods you can find and call for authorization purposes. PasswordSignInAsync() implements two-factor signin (also sets cookies; probably only when using AddIdentity() or AddDefaultIdentity()) and calls CheckPasswordSignInAsync(), which implements user lockout handling and calls UserManager.CheckPasswordAsync(), which just checks the password. So to get a proper authentication it's better not to call UserManager.CheckPasswordAsync() directly, but to do it through CheckPasswordSignInAsync(). But, in a single-factor JWT token scenario, calling PasswordSignInAsync() is probably not needed (and you can run into redirect issues). If you have included UseAuthentication()/AddAuthentication() in the Startup with the proper JwtBearer token schemes set, then the next time the client sends a request with a valid token attached, the authentication middleware will kick in, and the client will be 'signed in'; i.e. any valid JWT token will allow client to access controller actions protected with [Authorize].)

值得庆幸的是,IdentityServer与Identity完全分开.实际上,IdentityServer的合理实现是将其用作为您的服务发行令牌的独立文字身份服务器.但是,由于ASP.NET Core没有内置的令牌生成功能,因此很多人最终只能在他们的应用程序内部运行这个肿的服务器,以便能够使用JWT令牌,即使他们只有一个应用程序,也没有真正的用途.中央政府.我并不是要讨厌它,这是一个非常不错的解决方案,具有很多功能,但是对于更常见的用例来说,有一些简单的方法将是很好的.

And IdentityServer is thankfully completely separate from Identity. In fact the decent implementation of IdentityServer is to use it as a standalone literal identity server that issues tokens for your services. But since ASP.NET Core has no token generation capability built-in, a lot of people end up running this bloated server inside their apps just to be able to use JWT tokens, even though they have a single app and they have no real use for a central authority. I don't mean to hate on it, it's a really great solution with a lot of features, but it would be nice to have something simpler for the more common use cases.

这篇关于结合使用.NET Core Identity和API的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆