分类 Abp 下的文章

背景

使用abp vNext框架进行微服务开发时,使用了其中的Remote Service功能,本地调试没有任何问题,但是在部署到服务器时,在请求使用了远程服务调用的接口时,出现了如下错误提示。

https required.png

ERR] Could not retrieve the OpenId Connect discovery document! ErrorType: Exception. Error: Error connecting to http://10.0.0.101:5001/.well-known/openid-configuration. HTTPS required.
2020-10-21T02:40:36.618868530Z Volo.Abp.AbpException: Could not retrieve the OpenId Connect discovery document! ErrorType: Exception. Error: Error connecting to http://10.0.0.101:5001/.well-known/openid-configuration. HTTPS required.
2020-10-21T02:40:36.618916073Z    at Volo.Abp.IdentityModel.IdentityModelAuthenticationService.GetTokenEndpoint(IdentityClientConfiguration configuration)
2020-10-21T02:40:36.618928596Z    at Volo.Abp.IdentityModel.IdentityModelAuthenticationService.GetTokenResponse(IdentityClientConfiguration configuration)
...

很明显是ids4的该请求需要https方式,但是很多时候,该服务是内网环境调用,没必要https,二期内网环境调试也不方便。

但是我检查了配置,发现已经在模块初始化时,配置了 options.RequireHttpsMetadata = false;,而且一些需要认证的接口添加了[Authorize],也是可以正常使用的。

问题分析

也就是说,目前的情况,只有在远程服务调用时,才会出现。而该问题明显是在获取Identity Server4信息时出的错误。这样我们可以推断出,我们的模块中ConfigureServices配置的options.RequireHttpsMetadata = false;并不会对应用层调用远程服务生效。
我前去查看了abp 源码,找到了IdentityModelAuthenticationService类,关键代码如下:

protected virtual async Task<DiscoveryDocumentResponse> GetDiscoveryResponse(IdentityClientConfiguration configuration)
{
    using (var httpClient = HttpClientFactory.CreateClient(HttpClientName))
    {
        var request = new DiscoveryDocumentRequest
        {
            Address = configuration.Authority,
            Policy =
            {
                RequireHttps = configuration.RequireHttps
            }
        };
        IdentityModelHttpRequestMessageOptions.ConfigureHttpRequestMessage?.Invoke(request);
        return await httpClient.GetDiscoveryDocumentAsync(request);
    }
}

这样,一下子就明了了,我们在appsettings.json配置文件中,有两个认证服务的配置:

  "AuthServer": {
    "Authority": "http://x.x.x.x:5001",
    "ApiName": "IdentityService"
  },
  "IdentityClients": {
    "Default": {
      "GrantType": "client_credentials",
      "ClientId": "xxx-app",
      "ClientSecret": "1q2w3e*",
      "Authority": "http://x.x.x.x:5001",
      "Scope": "IdentityService InternalGateway xxx"
    }

第一个就是对应到了,上面提到的模块初始化时的AddAuthentication配置(当然你要是直接在源码中写死了,可能没有这一项),另一个才是对远程服务调用时起作用的配置内容。

解决

问题找到了就好办了,根据IdentityClientConfiguration 的结构,我们很容易猜出来,应该在IdentityClients配置中添加一项RequireHttps的item,并设置为false。修改后如下:

  "IdentityClients": {
    "Default": {
      "GrantType": "client_credentials",
      "ClientId": "xxx-app",
      "ClientSecret": "1q2w3e*",
      "RequireHttps": false,
      "Authority": "http://x.x.x.x:5001",
      "Scope": "IdentityService InternalGateway xxx"
    }
  }

背景

使用vNext搭建了项目,因项目需要给用户配置头像,但abp Zero模块中的User实体是不包含头像信息的,于是有了这个需求:扩展内置实体。为User表添加头像等信息。

步骤

1、新建MyUser类

该类用来定义新增的字段,不需要继承任何父类,如下所示:

public class MyUser
{
    #region const
    public const int MaxAvatarLength = 366;
    #endregion
        
    /// <summary>
    /// 头像
    /// </summary>
    public string Avatar { get; set; }

}

2、添加MyAppEfCoreEntityExtensionMappings类,

类名可以随意,但是按照惯例,一般以“项目名”+EfCoreEntityExtensionMappings命名。该类主要用来配置为IdentityUser新增字段,代码如下:

public static class MyAppEfCoreEntityExtensionMappings
{
    private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner();

    public static void Configure()
    {
        MyAppModulePropertyConfigurator.Configure();

        OneTimeRunner.Run(() =>
        {
            ObjectExtensionManager.Instance
                .MapEfCoreProperty<IdentityUser, string>(
                    nameof(User.Avatar),
                    (entityBuilder, propertyBuilder) =>
                    {
                        propertyBuilder.HasMaxLength(User.MaxAvatarLength);
                    }
                );
        });
    }
}

3、配置MyAppEntityFrameworkCoreModule模块中的PreConfigureServices

将上一步配置的内容,在模块中加载,代码如下:

public override void PreConfigureServices(ServiceConfigurationContext context)
{
    MyAppEfCoreEntityExtensionMappings.Configure();
    ...
    base.PreConfigureServices(context);
}

4、配置DbContextFactory类中的CreateDbContext

同上一步,在DbContextFactory中进行同样配置,一些情况下我们需要通过DbContextFactory来获取DbContext,如不配置此项,将会导致获取的DbContext中内容不一致。

public MyAppDbContext CreateDbContext(string[] args)
{
    MyAppEfCoreEntityExtensionMappings.Configure();
    return new MyAppDbContext(builder.Options);
}

5、配置应用层Dto扩展

因头像Avatar信息是我们追加给IdentityUser的,Abp Zero中内置的User相关Dto是没有此项内容的,我们需要对这些Dto做一些添加属性的操作。在Application.Contracts层,新建一个名为MyAppDtoExtensions的类,当然类名称随意。

public static class MyAppDtoExtensions
{
    private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner();

    public static void Configure()
    {
        OneTimeRunner.Run(() =>
        {
            ObjectExtensionManager.Instance
                .AddOrUpdateProperty<string>(
                    new[]
                    {
                        typeof(IdentityUserDto),
                        typeof(IdentityUserCreateDto),
                        typeof(IdentityUserUpdateDto),
                        typeof(ProfileDto),
                        typeof(UpdateProfileDto)
                    },
                    "Avatar"
                );
        });
    }
}

6、在模块类ApplicationContractsModule中进行配置

为了是上一步配置生效,还需要在MyAppApplicationContractsModule中进行如下配置:

public override void PreConfigureServices(ServiceConfigurationContext context)
{
    MyAppDtoExtensions.Configure();

}

自此,所有操作均已完成,可以重新生成迁移,更新数据库了。这里只演示了在User实体中添加头像,如需在其他内置的实体中添加字段,步骤一样。

Docker 启动容器时,使用如下命令方式即可。

docker run -it -d -p 5001:80 -p 5101:443 -e ASPNETCORE_URLS="https://+;http://+" -e ASPNETCORE_HTTPS_PORT=5101 -e ASPNETCORE_Kestrel__Certificates__Default__Password="abcdef" -e ASPNETCORE_Kestrel__Certificates__Default__Path=aaabbb.pfx --name=auth-server auth-server --restart always

错误提示: COPY failed: stat /var/lib/docker/tmp/docker-builder...no such file or directory

具体错误如下:

Step 4/5 : COPY /bin/Release/netcoreapp3.1/publish .
COPY failed: stat /var/lib/docker/tmp/docker-builder255452545/bin/Release/netcoreapp3.1/publish: no such file or directory

解决方案

看到此类错误,需要排查文件或文件夹名称是否有写错,如果一切正确,还需要查看是否配置了.dockerignore文件,并且要COPY的文件夹是否添加到了Ignore列表中,如果有,删除即可。

Docker容器做端口映射报错

docker: Error response from daemon: driver failed programming external connectivity on endpoint ....

解决方法

docker服务启动时定义的自定义链DOCKER被清除
重启即可systemctl restart docker


connect: permission denied

docker: docker: Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock ....

解决方法

修改 var/run/docker.sock的权限属性为666或777可解决。但,每次docker重启后,该权限将会重置,需要重新再次配置。


查看容器的日志

docker logs -f -t --tail 200 auth-server

以配置文件方式、守护态 运行redis ,同时,重启docker会自动启动

docker run -p 6379:6379 --name redis --restart always -v /root/redis/redis01/conf/redis.conf:/etc/redis/redis.conf -v /root/redis/redis01/data:/data -d redis redis-server /etc/redis/redis.conf --appendonly yes

Centos获取ip,无法使用ifconfig

ifconfig这个命令是在net-tools.x86_64这个包里,需要安装该工具,命令:yum install net-tools.x86_64

Docker 进入容器命令

docker exec -it 44fc0f0582d9 /bin/bash

查看容器ip地址:

[root@localhost ~]# docker inspect --format='{{.NetworkSettings.IPAddress}}' 1d3d739a0b3b
172.17.0.5
[root@localhost ~]# 

查看Linux版本信息

cat /etc/issue

COPY failed: stat /var/lib/docker/tmp/docker-builder...no such file or directory

错误如下:

Step 4/5 : COPY /bin/Release/netcoreapp3.1/publish .
COPY failed: stat /var/lib/docker/tmp/docker-builder255452545/bin/Release/netcoreapp3.1/publish: no such file or directory

看到此类错误,需要排查文件或文件夹名称是否有写错,如果一切正确,还需要查看是否配置了.dockerignore文件,并且要COPY的文件夹是否添加到了Ignore列表中,如果有,删除即可。

容器无法访问外网问题

默认构建镜像时,使用的是bridge模式,需访问外网,可以指定网络为host

docker build -t ideology-usermanager . --network=host