我很努力地瞭解IdentityServer3,AzureAD和私有數據庫如何一起工作。最大的問題是如何處理重定向URI。IdentityServer3 + AzureAD和RedirectUri混淆
我的場景是我有一個獨立的IdentityServer3。它的工作是根據AzureAD或私人數據庫對用戶進行身份驗證。內的ID3服務器上的文件Startup.cs,我有以下ID連接代碼:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Map("/identity", s3App =>
{
s3App.UseIdentityServer(new IdentityServerOptions
{
SiteName = "3S",
SigningCertificate = Certificate.Load(),
Factory = new IdentityServerServiceFactory()
.UseInMemoryUsers(InMemoryUsers.Get())
.UseInMemoryClients(InMemoryClients.Get())
.UseInMemoryScopes(InMemoryScopes.Get()),
AuthenticationOptions = new AuthenticationOptions
{
EnablePostSignOutAutoRedirect = true,
EnableSignOutPrompt = false,
IdentityProviders = ConfigureAdditionalIdentityProviders
}
});
});
}
public static void ConfigureAdditionalIdentityProviders(IAppBuilder app, string signInAsType)
{
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
AuthenticationType = "AzureAd",
Caption = "Login",
ClientId = "4613ed32-xxxx-xxxx-xxxx-xxxxxxxxxxxx", // GUID of registered application on Azure
Authority = "https://login.microsoftonline.com/our-tenant-id/",
PostLogoutRedirectUri = "https://localhost:44348/identity",
RedirectUri = "https://localhost:44348/identity",
Scope = "openid email profile",
ResponseType = "id_token",
AuthenticationMode = AuthenticationMode.Passive,
SignInAsAuthenticationType = signInAsType,
TokenValidationParameters = new TokenValidationParameters
{
AuthenticationType = Constants.ExternalAuthenticationType,
ValidateIssuer = false
}
});
}
我不明白爲什麼ID3服務器將需要要麼RedirectUri或PostLogoutRedirectUri ......難道不應該從請求認證的應用程序「通過」?畢竟,我們想要回到應用程序,而不是ID3服務器。當然,我不認爲這是什麼原因導致我的問題,但很好理解爲什麼這些在這裏。
我會說,我已經「接近」這個工作。
當我的應用程序需要身份驗證請求對AzureAD的身份驗證時,我被重定向到Microsoft帳戶登錄屏幕以輸入我的工作帳戶的用戶名/密碼。我提交我的憑據,然後重定向到ID3服務器或我的應用程序,具體取決於上面的代碼中使用了哪個RedirectUri。
爲了論證,我們假設我使用我的應用程序的RedirectUri。我將被髮送回應用程序,但不會發送到最初提示身份驗證質詢的頁面,如果我點擊需要身份驗證的頁面,我會將其發送回AzureAD服務器以再次登錄,只有這次AzureAD將我識別爲已登錄。
不幸的是,似乎沒有在AzureAD重定向之後確認/設置SecurityTokenValidated通知。
下面是在應用程序Startup.cs找到的代碼:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = "https://localhost:44348/identity",
ClientId = "3af8e3ba-5a04-4acc-8c51-1d30f8587ced", // Local ClientID registered as part of the IdentityServer3 InMemoryClients
Scope = "openid profile roles",
RedirectUri = "http://localhost:52702/",
PostLogoutRedirectUri = "http://localhost:52702/",
ResponseType = "id_token",
SignInAsAuthenticationType = "Cookies",
UseTokenLifetime = false,
Notifications = new OpenIdConnectAuthenticationNotifications
{
SecurityTokenValidated = n =>
{
var id = n.AuthenticationTicket.Identity;
var givenName = id.FindFirst(Constants.ClaimTypes.GivenName);
var familyName = id.FindFirst(Constants.ClaimTypes.FamilyName);
var sub = id.FindFirst(Constants.ClaimTypes.Subject);
var roles = id.FindAll(Constants.ClaimTypes.Role);
var nid = new ClaimsIdentity(
id.AuthenticationType,
Constants.ClaimTypes.GivenName,
Constants.ClaimTypes.Role
);
nid.AddClaim(givenName);
nid.AddClaim(familyName);
nid.AddClaim(sub);
nid.AddClaims(roles);
nid.AddClaim(new Claim("application_specific", "Some data goes here. Not sure what, though."));
nid.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));
n.AuthenticationTicket = new AuthenticationTicket(nid, n.AuthenticationTicket.Properties);
return Task.FromResult(0);
},
RedirectToIdentityProvider = n =>
{
if (n.ProtocolMessage.RequestType != OpenIdConnectRequestType.LogoutRequest)
return Task.FromResult(0);
var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token");
if (idTokenHint != null)
{
n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
}
return Task.FromResult(0);
},
AuthenticationFailed = (context) =>
{
context.HandleResponse();
context.Response.Redirect("/Error/message=" + context.Exception.Message);
//Debug.WriteLine("*** AuthenticationFailed");
return Task.FromResult(0);
},
}
});
AntiForgeryConfig.UniqueClaimTypeIdentifier = Constants.ClaimTypes.Subject;
JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();
}
}
你會發現OpenIdConnectAuthenticationOptions還含有RedirectUri和PostLogoutRedirectUri其指向應用程序,但這些似乎並不重要。
當然,當我使用cookies的一面登錄時,一切都很完美 - 我看到了我對用戶的所有要求。而且,在微軟的電話上花費了一些時間,他們提出了ID3之外的解決方案,但這不是我們需要的方式。我們將有多個應用程序對我們的ID3進行身份驗證,因此我們需要在內部包含和控制流程。
我真的需要一些幫助,試圖找出這最後一英里問題。我知道我很接近,我只是一直盯着這麼長時間,我可能正盯着我的錯誤,而沒有看到它。
2016年10月22日編輯
進一步的測試和實現Serilog發現的問題與RedirectUri
和PostLogoutRedirectUri
導致我加入/identity
,其對應於app.Map設定值中的URI的結尾。這解決了我返回到IdentityServer3的「空白」頁面的問題,現在我返回到IdentityServer3登錄屏幕。 Azure AD仍然認爲我已登錄,但我沒有在應用程序中正確設置令牌。
我用你的插圖和代碼片斷來更改/驗證我正在使用的代碼。不幸的是,同樣的問題正在發生......一旦我對Azure AD進行身份驗證,我將被重定向到IdentityServer3,而不是根據需要應用到我的應用程序。我還驗證了IdentityServer3中的客戶端具有正確的RedirectUris和PostLogoutRedirectUris。我只是從不回到我的應用程序。 – rcastagna
由於上面的測試對我很好,我建議您通過** Fiddler **跟蹤HTTP請求/重定向/響應,以查看請求重定向到Identity Server3時是否存在錯誤消息。 –