使用 IdentityServer3 进行 Azure AD 身份验证的本地帐户和选项

Local account and option for Azure AD authentication using IdentityServer3

我是 IdentityServer 的新手。我们要求应用程序允许访问多个 Web API。截至目前,身份验证是在本地使用数据库完成的,还有其他方法可以通过 Azure AD 进行身份验证。

我希望我的仪表板应用程序使用 IdentityServer3(目前工作正常)或使用外部提供商(在本例中为 Azure AD)进行身份验证。

然而我不断收到

There is an error determining which application you are signing into. Return to the application and try again

服务器配置,我用的是CustomViewServicefound at here

我正在将 Azure AD 添加到外部提供商列表中:

app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{

  ClientId = "xxxxxx-xxx-xxx-xx-04ec8dbxxxx",
  Authority = "https://login.windows.net/[domain name]",
  RedirectUri = "https://localhost:44333/core",
  PostLogoutRedirectUri = "http://localhost:36336/",
  AuthenticationType = "Azure AD",
  Caption = "Azure AD",
  TokenValidationParameters = new TokenValidationParameters
  {
    NameClaimType = "name",
    RoleClaimType = "role"
  },
  SignInAsAuthenticationType = "Cookies",

  Notifications = new OpenIdConnectAuthenticationNotifications
  {
    MessageReceived = m =>
    {
      var split = m.ProtocolMessage.AccessToken;
      return Task.FromResult(0);
    },
    AuthenticationFailed = context =>
    {
      context.HandleResponse();
      context.Response.Redirect("/Error?message=" + context.Exception.Message);
      return Task.FromResult(0);
    },
    RedirectToIdentityProvider = (context) =>
    {
      context.ProtocolMessage.DomainHint = "[domain name here]";
      return Task.FromResult(0);
    }
  }
});

我看到 Azure AD 登录屏幕,之后应用程序在 https://localhost:44333/core/callback

转移回 IdentityServ3

我的客户在http://localhost:36336/

客户端配置为:

public void Configuration(IAppBuilder app)
{
  // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888
  JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();

  app.UseCookieAuthentication(new CookieAuthenticationOptions
  {
    AuthenticationType = "Cookies"
  });

  app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
  {
    ClientId = "mvc.owin.hybrid.2",
    Authority = "https://localhost:44333/core",
    RedirectUri = "http://localhost:36336/",
    PostLogoutRedirectUri = "http://localhost:36336/",
    ResponseType = "code id_token",
    Scope = "openid profile read write offline_access",

    TokenValidationParameters = new TokenValidationParameters
    {
      NameClaimType = "name",
      RoleClaimType = "role"
    },

    SignInAsAuthenticationType = "Cookies",

    Notifications = new OpenIdConnectAuthenticationNotifications
    {
      AuthorizationCodeReceived = async n =>
      {
        // use the code to get the access and refresh token
        var tokenClient = new TokenClient(
        "https://localhost:44333/core/connect/token",
        "mvc.owin.hybrid.2",
        "secret");

        var tokenResponse = await tokenClient.RequestAuthorizationCodeAsync(
        n.Code, n.RedirectUri);

        if (tokenResponse.IsError)
        {
          throw new Exception(tokenResponse.Error);
        }

        // use the access token to retrieve claims from userinfo
        var userInfoClient = new UserInfoClient(
        new Uri(n.Options.Authority + "/connect/userinfo"),
        tokenResponse.AccessToken);

        var userInfoResponse = await userInfoClient.GetAsync();

        // create new identity
        var id = new ClaimsIdentity(n.AuthenticationTicket.Identity.AuthenticationType);
        id.AddClaims(userInfoResponse.GetClaimsIdentity().Claims);

        id.AddClaim(new Claim("access_token", tokenResponse.AccessToken));
        id.AddClaim(new Claim("expires_at", DateTime.Now.AddSeconds(tokenResponse.ExpiresIn).ToLocalTime().ToString()));
        id.AddClaim(new Claim("refresh_token", tokenResponse.RefreshToken));
        id.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));
        id.AddClaim(new Claim("sid", n.AuthenticationTicket.Identity.FindFirst("sid").Value));

        n.AuthenticationTicket = new AuthenticationTicket(
        new ClaimsIdentity(id.Claims, n.AuthenticationTicket.Identity.AuthenticationType, "name", "role"),
        n.AuthenticationTicket.Properties);
      },

      RedirectToIdentityProvider = n =>
      {
        // if signing out, add the id_token_hint
        if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
        {
          var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token");

          if (idTokenHint != null)
          {
            n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
          }
        }

        return Task.FromResult(0);
      }
    }
  });
}

设法解决了。

我忘了实现 AspNetIdentityUserService 方法 AuthenticateExternalAsync

一旦我将用户和声明从 Azure 映射到本地用户,它就起作用了。

此外,如果您需要隐藏本地登录屏幕并希望您的客户端直接转到 Azure AD 登录屏幕,请确保在客户端属性中将 EnableLocalLogin 设置为 false