grpc-dotnet身份验证jwt承载令牌

时间:2020-08-29 21:38:17

标签: c# asp.net-core authentication jwt grpc-dotnet

我正在寻找一些反馈或指导。我已经在dotnet core 3.1中构建了grpc服务器和客户端。仅此客户端将与服务器通信,但仍需要保护服务器端点。我正在尝试对其实施身份验证安全性,而jwt承载令牌似乎是一条不错的路径。我正在尝试遵循示例here(来自此MS Doc),该示例看似非常简单,但由于任何人都可以访问generate令牌端点,因此似乎对生产使用不安全。我认为它可以修改和实现在get令牌请求上传递的共享机密。这似乎是个好方法还是其他想法?

除了这一部分,我还有一个我不太了解的关于客户端代码的问题。在客户端启动时,它通过调用CreateAuthenticatedChannel()建立一个grpc通道,该通道似乎仅在设置了_token时添加承载令牌。在客户端启动并点击第三个数字之前,您不会获得令牌,但是我看不到通道或客户端在何处重建以包含元数据令牌值。该示例似乎可以工作,但不了解。

class Program
{
    // The port number(5001) must match the port of the gRPC server.
    private const string Address = "localhost:5001";

    private static string _token;

    static async Task Main(string[] args)
    {
        var channel = CreateAuthenticatedChannel($"https://{Address}");
        var client = new Ticketer.TicketerClient(channel);

        Console.WriteLine("gRPC Ticketer");
        Console.WriteLine();
        Console.WriteLine("Press a key:");
        Console.WriteLine("1: Get available tickets");
        Console.WriteLine("2: Purchase ticket");
        Console.WriteLine("3: Authenticate");
        Console.WriteLine("4: Exit");
        Console.WriteLine();

        var exiting = false;
        while (!exiting)
        {
            var consoleKeyInfo = Console.ReadKey(intercept: true);
            switch (consoleKeyInfo.KeyChar)
            {
                case '1':
                    await GetAvailableTickets(client);
                    break;
                case '2':
                    await PurchaseTicket(client);
                    break;
                case '3':
                    _token = await Authenticate();
                    break;
                case '4':
                    exiting = true;
                    break;
            }
        }

        Console.WriteLine("Exiting");
    }

    private static GrpcChannel CreateAuthenticatedChannel(string address)
    {
        var credentials = CallCredentials.FromInterceptor((context, metadata) =>
        {
            if (!string.IsNullOrEmpty(_token))
            {
                metadata.Add("Authorization", $"Bearer {_token}");
            }
            return Task.CompletedTask;
        });

        // SslCredentials is used here because this channel is using TLS.
        // Channels that aren't using TLS should use ChannelCredentials.Insecure instead.
        var channel = GrpcChannel.ForAddress(address, new GrpcChannelOptions
        {
            Credentials = ChannelCredentials.Create(new SslCredentials(), credentials)
        });
        return channel;
    }

    private static async Task<string> Authenticate()
    {
        Console.WriteLine($"Authenticating as {Environment.UserName}...");
        var httpClient = new HttpClient();
        var request = new HttpRequestMessage
        {
            RequestUri = new Uri($"https://{Address}/generateJwtToken?name={HttpUtility.UrlEncode(Environment.UserName)}"),
            Method = HttpMethod.Get,
            Version = new Version(2, 0)
        };
        var tokenResponse = await httpClient.SendAsync(request);
        tokenResponse.EnsureSuccessStatusCode();

        var token = await tokenResponse.Content.ReadAsStringAsync();
        Console.WriteLine(token);
        Console.WriteLine("Successfully authenticated.");

        return token;
    }

    private static async Task PurchaseTicket(Ticketer.TicketerClient client)
    {
        Console.WriteLine("Purchasing ticket...");
        try
        {
            var response = await client.BuyTicketsAsync(new BuyTicketsRequest { Count = 1 });
            if (response.Success)
            {
                Console.WriteLine("Purchase successful.");
            }
            else
            {
                Console.WriteLine("Purchase failed. No tickets available.");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error purchasing ticket." + Environment.NewLine + ex.ToString());
        }
    }

    private static async Task GetAvailableTickets(Ticketer.TicketerClient client)
    {
        Console.WriteLine("Getting available ticket count...");
        var response = await client.GetAvailableTicketsAsync(new Empty());
        Console.WriteLine("Available ticket count: " + response.Count);
    }
}

}

0 个答案:

没有答案