OpenId with IdentityServer4



我正在进行一个项目,我们希望使用IdentityServer4作为令牌服务器,并在此令牌服务器中对其他服务进行身份验证。我在Windows上使用Docker和linux容器开发环境。我配置了IdentityServer,它正在工作,我配置了Api客户端,它正在运行,但当我配置MVC客户端进行身份验证时,它无法通过docker访问令牌服务器。好吧,我意识到Docker的工作方式是有外部/内部端口的,所以我用这种方式配置了api和mvc客户端。

MVC客户端

services.AddAuthentication(opts =>
{
opts.DefaultScheme = "Cookies";
opts.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies", opts =>
{
opts.SessionStore = new MemoryCacheTicketStore(
configuration.GetValue<int>("AppSettings:SessionTimeout"));
})
.AddOpenIdConnect("oidc", opts =>
{
opts.ResponseType = "code id_token";
opts.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
opts.ClientId = "Mvc.Application";
opts.ClientSecret = "Secret.Mvc.Application";
opts.Authority = "http://authorization.server/";
//opts.Authority = "http://localhost:5001/";
//opts.MetadataAddress = "http://authorization.server/";
opts.UsePkce = true;
opts.SaveTokens = true;
opts.RequireHttpsMetadata = false;
opts.GetClaimsFromUserInfoEndpoint = true;
opts.Scope.Add("offline_access");
opts.Scope.Add("Services.Business");
opts.ClaimActions.MapJsonKey("website", "website");
});

这部分正在工作,因为文档发现正在工作但是它将无法访问http://authorization.serverurl,因为它是内部容器地址,不能通过web浏览器外部访问。因此,我尝试设置了两个不同的URL:MetadataAddress和Authority,MetadataAddress应该从OpenId服务器中提取文档,Authority将重定向所有未经授权的请求。然而,当我在调用AddOpenIdConnect时在OpenIdConnectOptions中同时设置MetadataAddress和Authority时,它将使用MetadataAddress而不是Authority。我检查了日志,文档的发现是成功的,因为我正在http://authorization.server/.well-known...,但它也启动了对IdentityServer的请求,以使用相同的url进行身份验证http://authorization.server/connect...

Api客户端

services.AddAuthorization()
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(opts =>
{
opts.RequireHttpsMetadata = false;
opts.ApiName = "Api.Services.Business";
opts.ApiSecret = "Secret.Api.Services.Business";
opts.Authority = "http://authorization.server/";
});

使用内部容器地址可以正常工作。

IdentityServer配置

services.AddIdentityServer(opt =>
{
opt.IssuerUri = "http://authorization.server/";
})
.AddAspNetIdentity<User>()
.AddSigningCredential(Certificate.Get())
.AddProfileService<IdentityProfileService>()
.AddInMemoryApiResources(Configuration.ApiResources())
.AddInMemoryIdentityResources(Configuration.IdentityResources())
.AddInMemoryClients(Configuration.Clients());

配置.cs

public static IEnumerable<Client> Clients(string redirectUri, string allowedCorsOrigins)
{
return new List<Client>
{
new Client
{
ClientId = "Services.Business",
ClientName = "Api Business",
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
AllowedScopes = 
{ 
"Services.Business"
},
ClientSecrets = 
{ 
new Secret("Secret.Services.Business".Sha256()) 
}
},              
new Client
{ 
ClientId = "Mvc.Application",
ClientName = "Mvc Application",                    
RequireConsent = false,
AllowOfflineAccess = true,
AllowedGrantTypes = GrantTypes.Hybrid,
AllowedScopes =
{
"Services.Business",
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile
},
ClientSecrets =
{
new Secret("Secret.Mvc.Application".Sha256())
},
RedirectUris = 
{ 
$"{redirectUri}/signin-oidc"
},
PostLogoutRedirectUris = 
{
$"{redirectUri}/signout-callback-oidc"
}
}
};
}

Docker compose.yml

version: '3.4'
networks:
fmnetwork:
driver: bridge
services:
authorization.server:
image: authorization.server
container_name: svc.authorization.server
build:
context: .
dockerfile: Authorization.Server/Dockerfile
ports:
- "5000:80"
- "5100:443"
environment:
ASPNETCORE_HTTPS_PORT: 5100
ASPNETCORE_ENVIRONMENT: Staging
ASPNETCORE_URLS: "https://+;http://+"
ASPNETCORE_Kestrel__Certificates__Default__Password: "devcertaspnet"
ASPNETCORE_Kestrel__Certificates__Default__Path: /root/.dotnet/https/aspnetapp.pfx
depends_on:
- sql.server
volumes:
- D:DockerDataFm:/root/.dotnet/https
- D:DockerDataFmLogs:/Fm.Logs
networks:
- fmnetwork
services.business:
image: services.business
container_name: api.services.business
build:
context: .
dockerfile: Services.Business/Dockerfile
ports:
- "5001:80"
- "5101:443"
environment:
ASPNETCORE_ENVIRONMENT: Staging
ASPNETCORE_HTTPS_PORT: 5101
ASPNETCORE_URLS: "https://+;http://+"
ASPNETCORE_Kestrel__Certificates__Default__Password: "devcertaspnet"
ASPNETCORE_Kestrel__Certificates__Default__Path: /root/.dotnet/https/aspnetapp.pfx
depends_on:
- sql.server
volumes:
- D:DockerDataFm:/root/.dotnet/https
- D:DockerDataFmLogs:/Fm.Logs
networks:
- fmnetwork
mvc.application:
image: mvc.application
container_name: svc.mvc.application
build:
context: .
dockerfile: Mvc.Application/Dockerfile
ports:
- "5002:80"
- "5102:443"
environment:
ASPNETCORE_ENVIRONMENT: Staging
ASPNETCORE_HTTPS_PORT: 5102
ASPNETCORE_URLS: "https://+;http://+"
ASPNETCORE_Kestrel__Certificates__Default__Password: "devcertaspnet"
ASPNETCORE_Kestrel__Certificates__Default__Path: /root/.dotnet/https/aspnetapp.pfx
volumes:
- D:DockerDataFm:/root/.dotnet/https
- D:DockerDataFmLogs:/Fm.Logs
networks:
- fmnetwork

我刚刚遇到了同样的问题,并能够按如下方式解决它。

需要记住的一些事项:

  • 这不是Identity Server本身的问题,而是容器看到的内部Docker URL(http://authorization.server(与浏览器看到的本地主机URL(http://localhost:5001(不匹配的问题
  • 您应该继续使用Identity Server(http://localhost:5001(的本地URL,并添加一个特殊情况来处理容器到容器的通信
  • 以下修复程序仅适用于使用Docker(Docker Compose、Kubernetes(进行开发时的,因此理想情况下,您应该检查环境(IsDevelopment扩展方法(,这样代码就不会在生产中使用

IdentityServer配置

services.AddIdentityServer(opt =>
{
if (Environment.IsDevelopment())
{
// It is not advisable to override this in production
opt.IssuerUri = "http://localhost:5001";
}
})

MVC客户端

services.AddAuthentication(... /*Omitted for brevity*/)
.AddOpenIdConnect("oidc", opts =>
{
// Your working, production ready configuration goes here
// It is important this matches the local URL of your identity server, not the Docker internal URL
options.Authority = "http://localhost:5001";
if (Environment.IsDevelopment())
{
// This will allow the container to reach the discovery endpoint
opts.MetadataAddress = "http://authorization.server/.well-known/openid-configuration";
opts.RequireHttpsMetadata = false;
opts.Events.OnRedirectToIdentityProvider = context =>
{
// Intercept the redirection so the browser navigates to the right URL in your host
context.ProtocolMessage.IssuerAddress = "http://localhost:5001/connect/authorize";
return Task.CompletedTask;
};
}
})

您可以通过配置传递所述URL来稍微调整代码。

最新更新