• 第三十七节:系统证书管理和gRPC基于数字证书的认证和授权


    一. 证书管理

    1. 如何生成证书

    (1). 关于阿里云证书和证书的相关概念

     详见:https://www.cnblogs.com/yaopengfei/p/10648151.html (抽时间重新配置一遍)

    (2). 本地生成测试证书

     详见:https://docs.microsoft.com/en-us/powershell/module/pkiclient/new-selfsignedcertificate?view=win10-ps

     这里使用案例9:【New-SelfSignedCertificate -Subject "localhost" -TextExtension @("2.5.29.17={text}DNS=localhost&IPAddress=127.0.0.1&IPAddress=::1")】

    2. 本地计算机证书管理

    (1).查看计算已有的证书

     cmd命令行→输入certmgr→可以查看当前用户下的证书以及受信任的颁发机构

    (2).证书导入和添加信任

     cmd命令行→输入mmc→进入控制台页面(默认空白)→选中文件中的‘添加/删除管理单元’→将'证书'一项添加进去

    导入步骤:

     A.以管理员的身份运行powershell,运行证书生成指令【New-SelfSignedCertificate -Subject "ypf" -TextExtension @("2.5.29.17={text}DNS=localhost&IPAddress=127.0.0.1&IPAddress=::1")】生成成功,如下图: 并在控制台下→个人→证书 找到刚才生成的证书。

     B.将该证书导出:选择需要私钥→输入密码123455→输入名称ypfCert进行导出

     C.对该证书添加信任:受信任的根证书颁发机构→证书→进行导入

    二. 基于证书的认证和授权

    1. 项目准备

     GrpcServer3:服务端

     MyClient3:客户端(控制台)

    2. 服务端配置

     (1).新建cert.proto文件,声明获取证书信息的方法GetCertificateInfo,并对其添加链接引用。

    代码如下:

    syntax = "proto3";
    
    import "google/protobuf/empty.proto";
    
    package certify;
    
    //Certifier对应CertifierService实现类
    service Certifier {
      //获取证书信息的方法
      rpc GetCertificateInfo (google.protobuf.Empty) returns (CertificateInfoResponse);
       //获取证书信息的方法(测试不加校验)
      rpc GetCertificateInfoNoAuth (google.protobuf.Empty) returns (CertificateInfoResponse);
    }
    
    message CertificateInfoResponse {
      bool hasCertificate = 1;
      string name = 2;
    }
    View Code

     (2).新建CertifierService,重写GetCertificateInfo方法,并添加授权校验 [Authorize(AuthenticationSchemes = "Certificate")]

    代码如下:

        /// <summary>
        /// cert.proto实现类
        /// </summary>
        public class CertifierService: CertifierBase
        {
            [Authorize(AuthenticationSchemes = "Certificate")]
            public override Task<CertificateInfoResponse> GetCertificateInfo(Empty request, ServerCallContext context)
            {
                var httpContext = context.GetHttpContext();
                var clientCertificate = httpContext.Connection.ClientCertificate;
                Console.WriteLine(clientCertificate);
                var name = string.Join(',', context.AuthContext.PeerIdentity.Select(i => i.Value));
                var certificateInfo = new CertificateInfoResponse
                {
                    HasCertificate = context.AuthContext.IsPeerAuthenticated,
                    Name = name
                };
                return Task.FromResult(certificateInfo);
            }
    
            /// <summary>
            /// 不加校验
            /// 和上面比较不加校验的情况
            /// </summary>
            /// <param name="request"></param>
            /// <param name="context"></param>
            /// <returns></returns>
            public override Task<CertificateInfoResponse> GetCertificateInfoNoAuth(Empty request, ServerCallContext context)
            {
                var certificateInfo = new CertificateInfoResponse
                {
                    Name = "看看能不能通过哦"
                };
                return Task.FromResult(certificateInfo);
            }
        }
    View Code

     (3).通过nuget安装程序集【Microsoft.AspNetCore.Authentication.Certificate】,在ConfigureService注册授权和认证中间件,在Configure开启认证和授权中间件,并映射CertifierService服务。

    代码如下:

      public void ConfigureServices(IServiceCollection services)
            {
                services.AddGrpc();
    
                //认证
                services.AddAuthentication("Certificate").AddCertificate(options =>
                {
                   // Not recommended in production environments. The example is using a self-signed test certificate.
                  options.RevocationMode = X509RevocationMode.NoCheck;
                  options.AllowedCertificateTypes = CertificateTypes.All;
                 });
                //授权
                services.AddAuthorization();
    
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
    
                app.UseRouting();
    
                //认证
                app.UseAuthentication();
                //授权
                app.UseAuthorization();
    
                app.UseEndpoints(endpoints =>
                {
                    //映射grpc实现类
                    endpoints.MapGrpcService<CertifierService>();
    
                    endpoints.MapGet("/", async context =>
                    {
                        await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
                    });
                });
            }
    View Code

     (4).在Program类中配置允许所有证书:httpsOptions.ClientCertificateMode = ClientCertificateMode.AllowCertificate;

    代码如下:

       public static IHostBuilder CreateHostBuilder(string[] args) =>
                Host.CreateDefaultBuilder(args)
                    .ConfigureWebHostDefaults(webBuilder =>
                    {
                        //允许所有证书
                        webBuilder.ConfigureKestrel(kestrelOptions =>
                        {
                            kestrelOptions.ConfigureHttpsDefaults(httpsOptions =>
                            {
                                httpsOptions.ClientCertificateMode = ClientCertificateMode.AllowCertificate;
                            });
                        });
    
                        webBuilder.UseStartup<Startup>();
                    });
    View Code

    (PS:此处也可以配置 httpsOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificate; 对于没有证书请求,直接中断链接,而不是403未授权了)

    3. 客户端配置

     (1).对cert.proto文件添加服务链接引用,会自动安装相应的程序集(版本可能不是最新的,需要手动更新一下)。

     (2).把前面导出来的证书ypfCert.pfx复制进来,并将属性改为"始终复制"。

     (3).编写无证书的调用代码 和 有证书的调用代码.

    代码如下:

     class Program
        {
            static async Task Main(string[] args)
            {
                Console.WriteLine("----------------------------下面是无证书的请求------------------------------------");
                try
                {          
                    var channel = GrpcChannel.ForAddress("https://localhost:5001");
                    var client = new Certifier.CertifierClient(channel);
                    var certificateInfo = await client.GetCertificateInfoAsync(new Empty());
                    Console.WriteLine($"返回信息HasCertificate={certificateInfo.HasCertificate},certificate name={certificateInfo.Name}");
    
                }
                catch (RpcException ex)
                {
                    Console.WriteLine($"gRPC error from calling service: {ex.Status.Detail}");
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"无证书:{ex.Message}");
                }
    
    
                Console.WriteLine("----------------------------下面是有证书的请求------------------------------------");
                try
                {
                    //证书相关配置
                    var handler = new HttpClientHandler();
                    var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);
                    var certPath = Path.Combine(basePath!, "MyCerts", "ypfCert.pfx");
                    var clientCertificate = new X509Certificate2(certPath, "123456");
                    handler.ClientCertificates.Add(clientCertificate);
                    //携带证书创建通道
                    var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions
                    {
                        HttpClient = new HttpClient(handler)
                    });
                    var client = new Certifier.CertifierClient(channel);
                    var certificateInfo = await client.GetCertificateInfoAsync(new Empty());
                    Console.WriteLine($"请求成功,返回信息:HasCertificate={certificateInfo.HasCertificate},certificate name={certificateInfo.Name}");
    
                }
                catch (RpcException ex)
                {
                    Console.WriteLine($"gRPC error from calling service: {ex.Status.Detail}");
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"有证书:{ex.Message}");
                }
    
    
                Console.WriteLine("----------------------------下面是不加校验 不传证书的测试------------------------------------");
                try
                {
                    var channel = GrpcChannel.ForAddress("https://localhost:5001");
                    var client = new Certifier.CertifierClient(channel);
                    var certificateInfo = await client.GetCertificateInfoNoAuthAsync(new Empty());
                    Console.WriteLine($"返回信息certificate name={certificateInfo.Name}");
    
                }
                catch (RpcException ex)
                {
                    Console.WriteLine($"gRPC error from calling service: {ex.Status.Detail}");
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"无证书:{ex.Message}");
                }
                Console.ReadKey();
            }
        }
    View Code

    4. 测试

     将GrpcServer3和MyClient3配置同时启动,查看结果,然后把服务端配置改为 httpsOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificate,再次运行查看结果。

    测试1:(ClientCertificateMode.AllowCertificate)

    测试2:(ClientCertificateMode.RequireCertificate)

     

    !

    • 作       者 : Yaopengfei(姚鹏飞)
    • 博客地址 : http://www.cnblogs.com/yaopengfei/
    • 声     明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
    • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
     
  • 相关阅读:
    135.002 智能合约设计-——多员工薪酬系统
    131.007 Unsupervised Learning
    131.006 Unsupervised Learning
    131.005 Unsupervised Learning
    135.001 智能合约设计-——单员工薪酬系统
    131.004 监督学习项目 | 为CharityML寻找捐献者
    131.003 数据预处理之Dummy Variable & One-Hot Encoding
    Chromebook 阿里云ECS 配置 jupyter Notebook
    Python之实现迭代器协议
    使用生成器创建新的迭代模式
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/13403742.html
Copyright © 2020-2023  润新知