首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用多个API的IdentityServer4创建用户

使用多个API的IdentityServer4创建用户
EN

Stack Overflow用户
提问于 2019-02-02 14:21:16
回答 3查看 7.3K关注 0票数 7

所以我在这个问题上已经有一段时间了。

我们有一个web应用程序,它使用IdentityServer4AspNetIdentity对用户进行身份验证和注册(这是按照预期进行的)。此外,我们还有另一个API (在同一解决方案中),它能够使用IdentityServer4对访问API的用户进行身份验证。

但是,问题是,除了身份验证之外,我们不能使用API来创建新用户

例如,用户应该能够通过web创建其他用户,而不仅仅是通过web应用程序创建其他用户,因为在我们的示例中,用户被链接到其他用户(将其视为多个概要文件)。

我不太熟悉所有提出.Net核心框架的配置服务,我尝试了多种方式通过API访问web应用程序的用户管理器,通过经典的POST请求注册我的用户,但似乎没有什么效果。在线搜索是很棘手的,因为我们的问题是非常具体的,这就是为什么我在这里张贴。

API Startup.cs - ConfigureServices:

代码语言:javascript
复制
services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
     // base-address of your identityserver
     options.Authority = Configuration["IdentityServer:Url"];

     // name of the API resource
     options.ApiName = Configuration["IdentityServer:APIName"];
     options.ApiSecret = Configuration["IdentityServer:APISecret"];

     options.EnableCaching = true;
     options.CacheDuration = TimeSpan.FromMinutes(10); // that's the default

     options.RequireHttpsMetadata = Convert.ToBoolean(Configuration["IdentityServer:RequireHttpsMetadata"]);
});

API Startup.cs -配置:

代码语言:javascript
复制
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseCors("AllowAllOrigins");
    app.UseAuthentication();
    app.UseMvc();
}

API UsersController.cs -构造器:

代码语言:javascript
复制
private readonly UserManager<ApplicationUser> _userManager;
private readonly ApplicationDbContext _context;

public UsersController(IUserService service,
ApplicationDbContext context,
UserManager<ApplicationUser> userManager)
{
    _service = service;
    _userManager = userManager;
    _context = context;
}

现在的问题是,当我启动API并尝试访问UsersController时,会得到以下错误:

代码语言:javascript
复制
System.InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Identity.UserManager`1[XXXXX.Data.Models.ApplicationUser]' while attempting to activate 'XXXXXXX.Api.Controllers.UsersController'.

我真诚地希望我至少能找到一些关于如何去做的建议。

如果有什么不清楚的答复,我会非常乐意添加更多的信息或明确的事情。

致以亲切的问候,

马里奥斯。

编辑:感谢您的回复。下面@Vidmantas提供的代码片段完成了这个任务。

由于我对.net核心的了解有限,我在配置服务功能方面做了很多尝试和错误,正如您可以想象的那样,这些功能没有工作。我坚信使用.net内核是一种简单的方法(例如API),但在配置服务时,复杂性(主要是令人费解/令人困惑)急剧增加。

至于架构,您给了我关于未来重构的好主意。记笔记。

马里奥斯。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-02-02 19:21:19

如果我对您的理解是正确的,那么您就不应该通过API来创建用户--这就是为什么您已经设置了Identity Server 4--为您的用户群提供身份验证的中心权限。你真正需要的是:

  • 标识服务器4端用于管理AspNetIdentity的一组API端点
  • 全新的API,但它与您的AspNetIdentity的Identity Server 4共享相同的数据库
  • 让API共享AspNet标识的数据库

如果您使用最后一个选项,那么您可能需要如下所示来添加以下内容:

代码语言:javascript
复制
services.AddDbContext<IdentityContext>(); //make sure it's same database as IdentityServer4

services.AddIdentityCore<ApplicationUser>(options => { });
new IdentityBuilder(typeof(ApplicationUser), typeof(IdentityRole), services)
    .AddRoleManager<RoleManager<IdentityRole>>()
    .AddSignInManager<SignInManager<ApplicationUser>>()
    .AddEntityFrameworkStores<IdentityContext>();

这将为您提供足够的服务来使用UserManager,并且不会设置任何不必要的身份验证方案。

由于关注点的分离,我不推荐最后一种方法--您的API应该关注提供资源,而不是创建用户和提供资源。第一和第二种方法在我看来是可以的,但我总是倾向于为AspNetIdentity管理提供干净的单独服务。

我们在其中一个项目中实现了这样的方法,这是一个示例体系结构:

  • auth.somedomain.com - IdentityServer4 web应用程序与AspNetIdentity用于用户身份验证。
  • accounts.somedomain.com -带有AspNetIdentity (与Identity Server 4相同数据库)的web应用程序,用于AspNetIdentity用户管理
  • webapp1.somedomain.com --一个所有前端逻辑都驻留在其中的web应用程序(当然,如果AspNetCore MVC或类似的东西,也可以有后端)。
  • api1.somedomain.com --一个纯粹出于API目的的web应用程序(如果您使用单个应用程序作为前端和后端,那么您可以将最后两个应用程序组合起来)。
票数 18
EN

Stack Overflow用户

发布于 2019-02-04 11:44:01

我和你有类似的情况。

  • 带有asp .net标识用户的标识服务器。(DB包含客户端和用户数据)
  • .net框架(数据库包含对应用程序数据的访问)
  • 应用.net框架。

我们的用例是,通常新用户将通过身份服务器创建。但是,我们也希望应用程序能够邀请用户。所以我可以登录申请,我想邀请我的朋友。这样的想法是,邀请的行为就像用户自己创建自己一样。

因此,它会发送一封电子邮件给我的朋友,并附上一个密码,然后用户将能够提供他们的密码,并有一个帐户。

为此,我在我的帐户控制器上创建了一个新的操作。

代码语言:javascript
复制
[HttpGet]
    [AllowAnonymous]
    public async Task<IActionResult> Invited([FromQuery] InviteUserRequest request)
    {

        if (request.Code == null)
        {
            RedirectToAction(nameof(Login));
        }
        var user = await _userManager.FindByIdAsync(request.UserId.ToString());
        if (user == null)
         {
          return View("Error");
        }

        var validateCode = await _userManager.VerifyUserTokenAsync(user, _userManager.Options.Tokens.PasswordResetTokenProvider, "ResetPassword", Uri.UnescapeDataString(request.Code));
        if (!validateCode)
        {
         return RedirectToAction(nameof(Login), new { message = ManageMessageId.PasswordResetFailedError, messageAttachment = "Invalid code." });
        }

        await _userManager.EnsureEmailConfirmedAsync(user);
        await _userManager.EnsureLegacyNotSetAsync(user);

        return View(new InvitedViewModel { Error = string.Empty, Email = user.Email, Code = request.Code, UserId = user.Id });
    }

当用户接受电子邮件时,我们会添加它们。

代码语言:javascript
复制
[HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Invited([FromForm] InvitedViewModel model)
    {
        if (!ModelState.IsValid)
        {
            model.Error = "invalid model";
            return View(model);
        }

        if (!model.Password.Equals(model.ConfirmPassword))
        {

            model.Error = "Passwords must match";
            return View(model);
        }
        if (model.Terms != null && !model.Terms.All(t => t.Accept))
        {
            return View(model);
        }
        var user = await _userManager.FindByEmailAsync(model.Email);
        if (user == null)
        {             
            // Don't reveal that the user does not exist
            return RedirectToAction(nameof(Login), new { message = ManageMessageId.InvitedFailedError, messageAttachment = "User Not invited please invite user again." });
        }

        var result = await _userManager.ResetPasswordAsync(user, Uri.UnescapeDataString(model.Code), model.Password);

        if (result.Succeeded)
        {            
            return Redirect(_settings.Settings.XenaPath);
        }

        var errors = AddErrors(result);
                    return RedirectToAction(nameof(Login), new { message = ManageMessageId.InvitedFailedError, messageAttachment = errors });
    }

这样做的原因是,只有身份服务器应该读取和写入其数据库。api和第三方应用程序不应该需要直接更改由另一个应用程序控制的数据库。因此,以这种方式,API告诉标识服务器邀请用户,然后身份服务器控制其他一切。

此外,通过这样做,它消除了API中有用户管理器的需求:)

票数 7
EN

Stack Overflow用户

发布于 2020-08-20 10:54:24

我不建议您在不同API之间使用共享数据库,如果您需要使用附加API扩展Identity Server 4,您可以使用LocalApiAuthentication作为控制器。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54493921

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档