Dr *_*ang 22 docker docker-compose identityserver4
我希望能够从docker机器外部和内部对Identity Server(STS)进行身份验证.
我在设置容器内外的正确权限时遇到问题.如果我将权限设置为内部名称,mcoidentityserver:5000则API可以进行身份验证,但客户端无法获取令牌,因为客户端位于docker网络之外.如果我将权限设置为外部名称,localhost:5000则客户端可以获取令牌,但API无法识别权限名称(因为localhost在这种情况下是主机).
我该如何设置权限?或许我需要调整码头网络?
我正在设置一个Windows 10 docker开发环境,它使用ASP.NET Core API(在Linux上),Identity Server 4(Linux上的ASP.NET Core)和PostgreSQL数据库.PostgreSQL不是问题,包含在图表中以保证完整性.它被映射到9876,因为我现在还在主机上运行了一个PostgreSQL实例.mco是我们公司的简称.
我一直在遵循Identity Server 4的说明来启动和运行.
我不包括docker-compose.debug.yml它,因为它运行的命令只与在Visual Studio中运行相关.
泊坞窗,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
Run Code Online (Sandbox Code Playgroud)
泊坞窗,compose.override.yml
这是由Visual Studio插件创建的,用于注入额外的值.
version: '2'
services:
mcoapi:
environment:
- ASPNETCORE_ENVIRONMENT=Development
ports:
- "80"
mcoidentityserver:
environment:
- ASPNETCORE_ENVIRONMENT=Development
ports:
- "5000"
Run Code Online (Sandbox Code Playgroud)
API Dockerfile
FROM microsoft/aspnetcore:1.1
ARG source
WORKDIR /app
EXPOSE 80
COPY ${source:-obj/Docker/publish} .
ENTRYPOINT ["dotnet", "Mco.Api.dll"]
Run Code Online (Sandbox Code Playgroud)
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"]
Run Code Online (Sandbox Code Playgroud)
API Startup.cs
我们告诉API使用Identity Server并设置权限.
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?}");
});
}
Run Code Online (Sandbox Code Playgroud)
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!");
});
}
}
Run Code Online (Sandbox Code Playgroud)
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" }
}
};
}
}
Run Code Online (Sandbox Code Playgroud)
客户
在控制台应用程序中运行.
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));
}
Run Code Online (Sandbox Code Playgroud)
提前致谢.
Ily*_*kov 12
确保IssuerUri设置为显式常量.我们在通过IP /主机名访问IdSrv4实例时遇到了类似的问题,并以这种方式解决了它:
services.AddIdentityServer(x =>
{
x.IssuerUri = "my_auth";
})
Run Code Online (Sandbox Code Playgroud)
PS为什么不统一权限URL hostname:5000?是的,如果符合以下条件,客户端和API都可以调用相同的URL hostname:5000:
hostname:5000(检查防火墙,网络拓扑等)DNS是最棘手的部分,所以如果你发现它有任何问题,我建议先从机器外部IP开始,而不是hostname.
为了完成这项工作,我需要在身份服务器实例上的docker-compose.yml和设置CORS中传入两个环境变量,以便允许API调用它.建立CORS不在这个问题的范围之内; 这个问题很好地涵盖了它.
身份服务器需要IDENTITY_ISSUER,这是身份服务器将给自己的名称.在这种情况下,我使用了IPdocker主机和身份服务器的端口.
mcoidentityserver:
image: mcoidentityserver
build:
context: ./Mco.IdentityServer
dockerfile: Dockerfile
environment:
IDENTITY_ISSUER: "http://10.0.75.1:5000"
ports:
- 5000:5000
networks:
- mconetwork
Run Code Online (Sandbox Code Playgroud)
API需要知道权限的位置.我们可以使用docker网络名称作为权限,因为调用不需要在docker网络之外,API只调用身份服务器来检查令牌.
mcoapi:
image: mcoapi
build:
context: ./Mco.Api
dockerfile: Dockerfile
environment:
IDENTITY_AUTHORITY: "http://mcoidentityserver:5000"
ports:
- 56107:80
links:
- mcodatabase
- mcoidentityserver
depends_on:
- "mcodatabase"
- "mcoidentityserver"
networks:
- mconetwork
Run Code Online (Sandbox Code Playgroud)
Identity Server.cs
您将身份颁发者名称设置为ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
var sqlConnectionString = Configuration.GetConnectionString("DefaultConnection");
services
.AddSingleton(Configuration)
.AddMcoCore(sqlConnectionString)
.AddIdentityServer(x => x.IssuerUri = Configuration["IDENTITY_ISSUER"])
.AddTemporarySigningCredential()
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients())
.AddCorsPolicyService<InMemoryCorsPolicyService>()
.AddAspNetIdentity<User>();
}
Run Code Online (Sandbox Code Playgroud)
API Startup.cs
我们现在可以将权限设置为环境变量.
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
{
Authority = Configuration["IDENTITY_AUTHORITY"],
RequireHttpsMetadata = false,
ApiName = "api1"
});
Run Code Online (Sandbox Code Playgroud)
如此处所示,docker-compose不适合生产,因为硬编码身份发布者是本地IP.相反,您需要一个正确的DNS条目,该条目将映射到docker实例,并在其中运行标识服务器.为此,我将创建一个docker-compose覆盖文件,并使用重写值构建生产.
感谢ilya-chumakov的帮助.
除此之外,我已经在我的博客上编写了使用Identity Server构建Linux docker + ASP.NET Core 2 + OAuth的整个过程.