为什么 IdentityServer 重定向到 http 而不是 https?
Why is IdentityServer redirecting to http rather than https?
我有一个非常简单的 MVC5 网站,我正在尝试使用 IdentityServer3 保护它。
我的网站和我的 IdentityServer 实例都作为单独的站点托管在 AppHarbor 中。两者都在 https 之后。
当我访问我网站中受 [Authorize]
属性(例如 /Home/About
)保护的资源时,我被成功重定向到 IdentityServer,并且我可以成功进行身份验证。
当 IdentityServer 将其响应 POST 回网站(通过 app.FormPostResponse.js
)时,网站会按预期响应 302 重定向到所请求的资源。但是,此重定向是 http,而不是 https(请参阅下面的网络跟踪)。
我确定这只是我的 IdentityServer 配置有问题,但如果有人指出我的错误,我将不胜感激。
(AppHarbor 在 IIS 前面使用反向代理(我相信是 nginx),SSL 在那里终止 - 所以根据 IdentityServer 文档,我有 RequireSsl = false
用于这种情况。)
这是我网站的 Startup.cs
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = "https://<my-idsrv3>.apphb.com/identity",
ClientId = "<my-client-id>",
Scope = "openid profile roles email",
RedirectUri = "https://<my-website>.apphb.com",
ResponseType = "id_token",
SignInAsAuthenticationType = "Cookies",
UseTokenLifetime = false
});
JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();
}
}
这是来自我的 IdentityServer3 实例的Startup.cs:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Map("/identity", idsrvApp =>
{
idsrvApp.UseIdentityServer(new IdentityServerOptions
{
SiteName = "My Identity Server",
SigningCertificate = Certificates.LoadSigningCertificate(),
RequireSsl = false,
PublicOrigin = "https://<my-idsrv3>.apphb.com",
Factory = new IdentityServerServiceFactory()
.UseInMemoryUsers(Users.Get())
.UseInMemoryClients(Clients.Get())
.UseInMemoryScopes(Scopes.Get())
});
});
}
}
这是我的网站客户端的定义:
new Client
{
Enabled = true,
ClientName = "My Website Client",
ClientId = "<my-client-id>",
Flow = Flows.Implicit,
RedirectUris = new List<string>
{
"https://<my-website>.apphb.com"
},
AllowAccessToAllScopes = true
}
这是在 IdentityServer 同意屏幕上单击 'Yes, Allow' 后来自 Chrome 的跟踪:
看来这个问题是由我的客户网站在 SSL 终止的 nginx 前端后面引起的。
参考this GitHub issue,我在网站应用程序配置的开头添加了以下内容:
app.Use(async (ctx, next) =>
{
string proto = ctx.Request.Headers.Get("X-Forwarded-Proto");
if (!string.IsNullOrEmpty(proto))
{
ctx.Request.Scheme = proto;
}
await next();
});
这让网站知道传入的请求是通过 https 发出的;这反过来似乎可以确保 IdentityServer3 中间件生成 https uri。
在 Azure 应用服务中遇到了同样的问题 运行 identityserver4。即使使用强制 https
,.well-known/openid-configuration
中生成的 url 仍然是 http://
.
使用与其他答案相同的解决方案修复,但使用 AspNetCore ForwardedHeadersExtensions
:
var forwardOptions = new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto,
// Needed because of mixing http and https.
RequireHeaderSymmetry = false,
};
// Accept X-Forwarded-* headers from all sources.
forwardOptions.KnownNetworks.Clear();
forwardOptions.KnownProxies.Clear();
app.UseForwardedHeaders(forwardOptions);
有关此主题的更多讨论,另请参阅 https://github.com/IdentityServer/IdentityServer4/issues/1331。
在您的启动项中添加转发headers
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost;
});
和
app.UseForwardedHeaders(new ForwardedHeadersOptions()
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
最后告诉配置它必须将重定向中的 http 替换为 https url。我仍在寻找更好的方法来实现它。
在你的 .addopenidconnect() 添加:
Func<RedirectContext, Task> redirectToIdentityProvider = (ctx) =>
{
if (!ctx.ProtocolMessage.RedirectUri.StartsWith("https") && !ctx.ProtocolMessage.RedirectUri.Contains("localhost"))
ctx.ProtocolMessage.RedirectUri = ctx.ProtocolMessage.RedirectUri.Replace("http", "https");
return Task.FromResult(0);
};
opt.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = redirectToIdentityProvider
};
我有一个非常简单的 MVC5 网站,我正在尝试使用 IdentityServer3 保护它。
我的网站和我的 IdentityServer 实例都作为单独的站点托管在 AppHarbor 中。两者都在 https 之后。
当我访问我网站中受 [Authorize]
属性(例如 /Home/About
)保护的资源时,我被成功重定向到 IdentityServer,并且我可以成功进行身份验证。
当 IdentityServer 将其响应 POST 回网站(通过 app.FormPostResponse.js
)时,网站会按预期响应 302 重定向到所请求的资源。但是,此重定向是 http,而不是 https(请参阅下面的网络跟踪)。
我确定这只是我的 IdentityServer 配置有问题,但如果有人指出我的错误,我将不胜感激。
(AppHarbor 在 IIS 前面使用反向代理(我相信是 nginx),SSL 在那里终止 - 所以根据 IdentityServer 文档,我有 RequireSsl = false
用于这种情况。)
这是我网站的 Startup.cs
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = "https://<my-idsrv3>.apphb.com/identity",
ClientId = "<my-client-id>",
Scope = "openid profile roles email",
RedirectUri = "https://<my-website>.apphb.com",
ResponseType = "id_token",
SignInAsAuthenticationType = "Cookies",
UseTokenLifetime = false
});
JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();
}
}
这是来自我的 IdentityServer3 实例的Startup.cs:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Map("/identity", idsrvApp =>
{
idsrvApp.UseIdentityServer(new IdentityServerOptions
{
SiteName = "My Identity Server",
SigningCertificate = Certificates.LoadSigningCertificate(),
RequireSsl = false,
PublicOrigin = "https://<my-idsrv3>.apphb.com",
Factory = new IdentityServerServiceFactory()
.UseInMemoryUsers(Users.Get())
.UseInMemoryClients(Clients.Get())
.UseInMemoryScopes(Scopes.Get())
});
});
}
}
这是我的网站客户端的定义:
new Client
{
Enabled = true,
ClientName = "My Website Client",
ClientId = "<my-client-id>",
Flow = Flows.Implicit,
RedirectUris = new List<string>
{
"https://<my-website>.apphb.com"
},
AllowAccessToAllScopes = true
}
这是在 IdentityServer 同意屏幕上单击 'Yes, Allow' 后来自 Chrome 的跟踪:
看来这个问题是由我的客户网站在 SSL 终止的 nginx 前端后面引起的。
参考this GitHub issue,我在网站应用程序配置的开头添加了以下内容:
app.Use(async (ctx, next) =>
{
string proto = ctx.Request.Headers.Get("X-Forwarded-Proto");
if (!string.IsNullOrEmpty(proto))
{
ctx.Request.Scheme = proto;
}
await next();
});
这让网站知道传入的请求是通过 https 发出的;这反过来似乎可以确保 IdentityServer3 中间件生成 https uri。
在 Azure 应用服务中遇到了同样的问题 运行 identityserver4。即使使用强制 https
,.well-known/openid-configuration
中生成的 url 仍然是 http://
.
使用与其他答案相同的解决方案修复,但使用 AspNetCore ForwardedHeadersExtensions
:
var forwardOptions = new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto,
// Needed because of mixing http and https.
RequireHeaderSymmetry = false,
};
// Accept X-Forwarded-* headers from all sources.
forwardOptions.KnownNetworks.Clear();
forwardOptions.KnownProxies.Clear();
app.UseForwardedHeaders(forwardOptions);
有关此主题的更多讨论,另请参阅 https://github.com/IdentityServer/IdentityServer4/issues/1331。
在您的启动项中添加转发headers
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost;
});
和
app.UseForwardedHeaders(new ForwardedHeadersOptions()
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
最后告诉配置它必须将重定向中的 http 替换为 https url。我仍在寻找更好的方法来实现它。
在你的 .addopenidconnect() 添加:
Func<RedirectContext, Task> redirectToIdentityProvider = (ctx) =>
{
if (!ctx.ProtocolMessage.RedirectUri.StartsWith("https") && !ctx.ProtocolMessage.RedirectUri.Contains("localhost"))
ctx.ProtocolMessage.RedirectUri = ctx.ProtocolMessage.RedirectUri.Replace("http", "https");
return Task.FromResult(0);
};
opt.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = redirectToIdentityProvider
};