如何在docker机器内部和外部使用IdentityServer4? [英] How can I use IdentityServer4 from inside and outside a docker machine?
问题描述
我希望能够从外部和外部通过
详细信息
我正在设置一个Windows 10 docker开发环境,该环境使用ASP.NET Core API(在Linux上),Identity Server 4(ASP.NET Core)在Linux上)和PostgreSQL数据库。 PostgreSQL没问题,为完整性起见,它包含在图中。它已映射到9876,因为我现在也有一个PostgreSQL实例在主机上运行。 mco
是我们公司的简称。
我一直在关注 Identity Server 4说明,以启动并运行。
< h2>代码
我不包含 docker-compose.debug.yml
,因为它具有相关的运行命令
docker-compose.yml
版本:'2'
服务:
mcodatabase:
图片:mcodatabase
生成:
上下文:./数据
dockerfile:Dockerfile
重新启动:始终
端口:
-9876:5432
环境:
POSTGRES_USER:mcodevuser
POSTGRES_PASSWORD:密码
POSTGRES_DB:mcodev
卷:
-postgresdata:/ var / lib / postgresql / data
网络:
-mconetwork
mcoidentityserver:
图像:mcoidentityserver
构建:
上下文:./Mco.IdentityServer
dockerfile:Dockerfile
端口:
-5000:5000
网络:
-mconetwork
mcoapi:
映像:mcoapi
生成:
上下文:./Mco.Api
dockerfile:Dockerfile
端口:
-56107:80
链接:
-mcodatabase
depends_on:
- mcodatabase
- mcoidentityserver
网络:
-mconetwork
数量:
postgresdata:
网络:
mconetwork:
驱动程序:桥接
docker-compose.override.yml
这是由Visual Studio插件创建的,用于注入额外的值。
版本:'2'
服务:
mcoapi:
环境:
-ASPNETCORE_ENVIRONMENT =开发
端口:
- 80
mcoidentityserver:
环境:
-ASPNETCORE_ENVIRONMENT =开发
端口:
- 5000
API Dockerfile
FROM microsoft / aspnetcore:1.1
ARG源
WORKDIR / app
EXPOSE 80
COPY $ {source:-obj / Docker / publish}。
ENTRYPOINT [ dotnet, Mco.Api.dll]
Identity Server Dockerfile
FROM microsoft / aspnetcore:1.1
ARG源
WORKDIR / app
COPY $ {source:-obj / Docker / publish}。
EXPOSE 5000
ENV ASPNETCORE_URLS http:// *:5000
ENTRYPOINT [ dotnet, Mco.IdentityServer.dll]
API Startup.cs
我们告诉API使用
public void Configure(IApplicationBuilder应用程序,IHostingEnvironment env,ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection( Logging));
loggerFactory.AddDebug();
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
{
// //无法运行,因为我们在docker中运行,并且不了解localhost:5000是什么! b $ b Authority = http:// localhost:5000,
RequireHttpsMetadata = false,
ApiName = api1
});
if(env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler( / Home / Error);
}
app.UseMvc(routes =>
{
route.MapRoute(
name: default,
模板: {controller = Home} / {action = Index} / {id?});
});
}
Identity Server Startup.cs
公共类启动
{
public void ConfigureServices(IServiceCollection服务)
{
服务。 AddIdentityServer()
.AddTemporarySigningCredential()
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients());
}
public void Configure(IApplicationBuilder app,IHostingEnvironment env,ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole();
if(env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseIdentityServer();
app.Run(async(context)=>
{
等待context.Response.WriteAsync( Hello World!);
});
}
}
Identity Server Config.cs >
公共类配置
{
public static IEnumerable< ApiResource> GetApiResources()
{
return new List< ApiResource>
{
新的ApiResource( api1,我的API)
};
}
公共静态IEnumerable< Client> GetClients()
{
返回新的List< Client>
{
新客户
{
ClientId = client,
//没有交互用户,使用clientid / secret进行认证
AllowedGrantTypes = GrantTypes.ClientCredentials,
//身份验证密钥
ClientSecrets =
{
new Secret( secret .Sha256())
},
//客户端有权访问
的范围AllowedScopes = { api1}
}
};
}
}
客户
在控制台应用程序中运行。
var发现= DiscoveryClient.GetAsync(本地主机:5000)。结果;
var tokenClient = new TokenClient(discovery.TokenEndpoint, client, secret);
var tokenResponse = tokenClient.RequestClientCredentialsAsync( api1)。Result;
if(tokenResponse.IsError)
{
Console.WriteLine(tokenResponse.Error);
返回1;
}
var client = new HttpClient();
client.SetBearerToken(tokenResponse.AccessToken);
var response = client.GetAsync( http:// localhost:56107 / test).Result;
if(!response.IsSuccessStatusCode)
{
Console.WriteLine(response.StatusCode);
}
else
{
var content = response.Content.ReadAsStringAsync()。Result;
Console.WriteLine(JArray.Parse(content));
}
谢谢。
确保 IssuerUri
设置为显式常量。通过IP /主机名访问Identity Server实例时,我们遇到了类似的问题,并通过以下方式解决了此问题:
services.AddIdentityServer(x = >
{
x.IssuerUri = my_auth;
})
PS为什么不将授权URL统一为 hostname:5000
?是的, Client 和 API 都可以调用相同的URL hostname:5000
,如果:
- 5000端口已暴露(我认为可以)
- 在Docker容器内解析了DNS。
- 您可以访问
主机名:5000
(检查防火墙,网络拓扑等)
DNS是最棘手的部分。如果您有任何问题,建议您尝试通过暴露的IP访问Identity Server,而不要解析主机名
。
I want to be able to authenticate against an Identity Server (STS) from outside and inside a docker machine.
I am having trouble with setting the correct authority that works both inside and outside the container. If I set the authority to the internal name mcoidentityserver:5000
then the API can authenticate but the client cannot get a token as the client lies outside of the docker network. If I set the authority to the external name localhost:5000
then the client can get a token but the API doesn't recognise the authority name (because localhost
in this case is host machine).
What should I set the Authority to? Or perhaps I need to adjust the docker networking?
Diagram
The red arrow is the part that I'm having trouble with.
Detail
I am setting up a Windows 10 docker development environment that uses an ASP.NET Core API (on Linux), Identity Server 4 (ASP.NET Core on Linux) and a PostgreSQL database. PostgreSQL isn't a problem, included in the diagram for completeness. It's mapped to 9876 because I also have a PostgreSQL instance running on the host for now. mco
is a shortened name of our company.
I have been following the Identity Server 4 instructions to get up and running.
Code
I'm not including the docker-compose.debug.yml
because it has run commands pertinent only to running in Visual Studio.
docker-compose.yml
version: '2'
services:
mcodatabase:
image: mcodatabase
build:
context: ./Data
dockerfile: Dockerfile
restart: always
ports:
- 9876:5432
environment:
POSTGRES_USER: mcodevuser
POSTGRES_PASSWORD: password
POSTGRES_DB: mcodev
volumes:
- postgresdata:/var/lib/postgresql/data
networks:
- mconetwork
mcoidentityserver:
image: mcoidentityserver
build:
context: ./Mco.IdentityServer
dockerfile: Dockerfile
ports:
- 5000:5000
networks:
- mconetwork
mcoapi:
image: mcoapi
build:
context: ./Mco.Api
dockerfile: Dockerfile
ports:
- 56107:80
links:
- mcodatabase
depends_on:
- "mcodatabase"
- "mcoidentityserver"
networks:
- mconetwork
volumes:
postgresdata:
networks:
mconetwork:
driver: bridge
docker-compose.override.yml
This is created by the Visual Studio plugin to inject extra values.
version: '2'
services:
mcoapi:
environment:
- ASPNETCORE_ENVIRONMENT=Development
ports:
- "80"
mcoidentityserver:
environment:
- ASPNETCORE_ENVIRONMENT=Development
ports:
- "5000"
API Dockerfile
FROM microsoft/aspnetcore:1.1
ARG source
WORKDIR /app
EXPOSE 80
COPY ${source:-obj/Docker/publish} .
ENTRYPOINT ["dotnet", "Mco.Api.dll"]
Identity Server Dockerfile
FROM microsoft/aspnetcore:1.1
ARG source
WORKDIR /app
COPY ${source:-obj/Docker/publish} .
EXPOSE 5000
ENV ASPNETCORE_URLS http://*:5000
ENTRYPOINT ["dotnet", "Mco.IdentityServer.dll"]
API Startup.cs
Where we tell the API to use the Identity Server and set the Authority.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
{
// This can't work because we're running in docker and it doesn't understand what localhost:5000 is!
Authority = "http://localhost:5000",
RequireHttpsMetadata = false,
ApiName = "api1"
});
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
Identity Server Startup.cs
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentityServer()
.AddTemporarySigningCredential()
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients());
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseIdentityServer();
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World!");
});
}
}
Identity Server Config.cs
public class Config
{
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource("api1", "My API")
};
}
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client
{
ClientId = "client",
// no interactive user, use the clientid/secret for authentication
AllowedGrantTypes = GrantTypes.ClientCredentials,
// secret for authentication
ClientSecrets =
{
new Secret("secret".Sha256())
},
// scopes that client has access to
AllowedScopes = { "api1" }
}
};
}
}
Client
Running in a console app.
var discovery = DiscoveryClient.GetAsync("localhost:5000").Result;
var tokenClient = new TokenClient(discovery.TokenEndpoint, "client", "secret");
var tokenResponse = tokenClient.RequestClientCredentialsAsync("api1").Result;
if (tokenResponse.IsError)
{
Console.WriteLine(tokenResponse.Error);
return 1;
}
var client = new HttpClient();
client.SetBearerToken(tokenResponse.AccessToken);
var response = client.GetAsync("http://localhost:56107/test").Result;
if (!response.IsSuccessStatusCode)
{
Console.WriteLine(response.StatusCode);
}
else
{
var content = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(JArray.Parse(content));
}
Thanks in advance.
Ensure IssuerUri
is set to an explicit constant. We had similar issues with accessing Identity Server instance by the IP/hostname and resolved it this way:
services.AddIdentityServer(x =>
{
x.IssuerUri = "my_auth";
})
P.S. Why don't you unify the authority URL to hostname:5000
? Yes, it is possible for Client and API both call the same URL hostname:5000
if:
- 5000 port is exposed (I see it's OK)
- DNS is resolved inside the docker container.
- You have access to
hostname:5000
(check firewalls, network topology, etc.)
DNS is the most tricky part. If you have any trouble with it I recommend you try reaching Identity Server by its exposed IP instead of resolving hostname
.
这篇关于如何在docker机器内部和外部使用IdentityServer4?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!