在从外部提供者进行身份验证后,如何验证用户是否存在于 IdentityServer4 中?

我正在尝试找到一种适当的方法,在从 Azure Active Directory 等外部身份提供者成功进行身份验证后,我可以注入服务以验证用户是否存在或在我的应用程序中注册。如果他的帐户尚未在我的应用程序中注册,我想要做的是将用户重定向到自定义错误页面或显示未经授权的消息。


我尝试使用 IProfileService 接口,但似乎不是正确的方法。


这是我的 Startup.cs 设置:


public void ConfigureServices(IServiceCollection services)

{

    services.AddMvc();


    services

        .AddIdentityServer()

        .AddDeveloperSigningCredential()

        .AddTestUsers(Config.GetUsers())

        .AddInMemoryIdentityResources(Config.GetIdentityResources())

        .AddInMemoryApiResources(Config.GetApiResources())

        .AddInMemoryClients(Config.GetClients()) // Client was configured with RequireConsent = false, EnableLocalLogin = false,

        .AddProfileService<ProfileService>()

        .Services.AddTransient<IUserRepository,UserRepository>();


    services.AddAuthentication()

        .AddOpenIdConnect("AAD", "Azure Active Directory", options =>

        {

            options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;

            options.SignOutScheme = IdentityServerConstants.SignoutScheme;

            options.Authority = "https://login.microsoftonline.com/MyTenant";

            options.ClientId = "MyClientId";

            options.TokenValidationParameters = new TokenValidationParameters

            {

                ValidateIssuer = false

            };


            options.GetClaimsFromUserInfoEndpoint = true;                    

        });

}



public class ProfileService : IProfileService

{

    private readonly IUserRepository _userRepository;


    public ProfileService(IUserRepository userRepository)

    {

        _userRepository = userRepository 

    }



是否有任何可用的服务或接口可以用来注入我的用户验证以及允许我在该服务中注入我的用户存储库?是否可以在 IdentityServer4 中注入这种进程?有人可以指出我使用 IdentityServer4 实现目标的正确方向吗?


注意:假设我有 SPA 网络应用程序,并且我有自己的单独注册机制。如果用户不存在,我不想重定向回我的 SPA,而是在 IdentityServer4 中处理它。顺便说一句,为简洁起见,上面的一些代码不包括在内。


叮当猫咪
浏览 231回答 2
2回答

潇湘沐

IdentityServer4 QuickStart UI 配置为在通过外部提供商登录时自动配置本地用户帐户。这一切都在处理ExternalController.Callback:// lookup our user and external provider infovar (user, provider, providerUserId, claims) = FindUserFromExternalProvider(result);if (user == null){&nbsp; &nbsp; // this might be where you might initiate a custom workflow for user registration&nbsp; &nbsp; // in this sample we don't show how that would be done, as our sample implementation&nbsp; &nbsp; // simply auto-provisions new external user&nbsp; &nbsp; user = AutoProvisionUser(provider, providerUserId, claims);}在您的情况下,您可以执行您需要执行的任何逻辑,而不是调用AutoProvisionUser. 由于这是正在执行的常规 MVC 操作,因此您可以将自己的类注入到ExternalController的构造函数中或注入到Callback自身中(使用[FromServices])。以下是您可能想要进行的更改的粗略想法:public async Task<IActionResult> Callback([FromServices] IUserRepository userRepository){&nbsp; &nbsp; ...&nbsp; &nbsp; // lookup our user and external provider info&nbsp; &nbsp; var (user, provider, providerUserId, claims) = FindUserFromExternalProvider(result);&nbsp; &nbsp; if (user == null)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; // We don't have a local user.&nbsp; &nbsp; &nbsp; &nbsp; return RedirectToAction("SomeAction", "SomeController");&nbsp; &nbsp; }&nbsp; &nbsp; ...}

回首忆惘然

如果您使用的是 ASP.NET Identity ,则可以在 inExternalLoginCallback函数中编写自定义逻辑。AccountController从 Azure AD 获得 JWT 令牌后,您可以解码令牌,获取用户声明,例如电子邮件/姓名:if (remoteError != null){&nbsp; &nbsp; ErrorMessage = $"Error from external provider: {remoteError}";&nbsp; &nbsp; return RedirectToAction(nameof(Login));}// read external identity from the temporary cookievar aadResult1 = await HttpContext.AuthenticateAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);if (aadResult1?.Succeeded != true){&nbsp; &nbsp; throw new Exception("External authentication error");}// retrieve claims of the external uservar externalUser = aadResult1.Principal;if (externalUser == null){&nbsp; &nbsp; throw new Exception("External authentication error");}// retrieve claims of the external uservar claims = externalUser.Claims.ToList();// try to determine the unique id of the external user - the most common claim type for that are the sub claim and the NameIdentifier// depending on the external provider, some other claim type might be usedvar userIdClaim = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Subject);if (userIdClaim == null){&nbsp; &nbsp; userIdClaim = claims.FirstOrDefault(x => x.Type == "http://schemas.microsoft.com/identity/claims/objectidentifier");}if (userIdClaim == null){&nbsp; &nbsp; throw new Exception("Unknown userid");}然后你可以在数据库中编写你的服务实现/逻辑来确认用户是否已经在数据库中。如果是,则登录用户;如果否,则将用户重定向到确认/注册视图。就像是:// Sign in the user with this external login provider if the user already has a login.var result = await _signInManager.ExternalLoginSignInAsync("YourProvider", userIdClaim.Value, isPersistent: false, bypassTwoFactor: true);if (result.Succeeded){&nbsp; &nbsp; _logger.LogInformation("User logged in with {Name} provider.", "YourProvider");&nbsp; &nbsp; // delete temporary cookie used during external authentication&nbsp; &nbsp; await HttpContext.SignOutAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);&nbsp; &nbsp; return RedirectToLocal(returnUrl);}if (result.IsLockedOut){&nbsp; &nbsp; return RedirectToAction(nameof(Lockout));}else{&nbsp; &nbsp; // If the user does not have an account, then ask the user to create an account.&nbsp; &nbsp; ViewData["ReturnUrl"] = returnUrl;&nbsp; &nbsp; ViewData["LoginProvider"] = "YourProvider";&nbsp; &nbsp; var email = claims.FirstOrDefault(x => x.Type == ClaimTypes.Upn).Value;&nbsp; &nbsp; return View("ExternalLogin", new ExternalLoginViewModel { Email = email });}如何将 AD 用户链接到本地数据库用户取决于您。使用 Azure AD 的对象 ID 或 UPN。
打开App,查看更多内容
随时随地看视频慕课网APP