如何在docker机器内部和外部使用IdentityServer4? [英] How can I use IdentityServer4 from inside and outside a docker machine?

查看:91
本文介绍了如何在docker机器内部和外部使用IdentityServer4?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望能够从外部和外部通过



详细信息



我正在设置一个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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆