本示例是基于GRPC框架下的认证代码与MVC模式稍有区别,直接上代码 服务端代码如下:
public void ConfigureServices(IServiceCollection services) { services.AddGrpc(); services.AddSingleton<TicketRepository>(); services.AddAuthorization(options => { options.AddPolicy(JwtBearerDefaults.AuthenticationScheme, policy => { policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme); policy.RequireClaim(ClaimTypes.Name); }); }); services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateAudience = true, //验证受众 ValidateIssuer = true, //验证签发人 ValidateActor = true, //验证签名 ValidateLifetime = true, //是否在令牌生存期间验证 ValidIssuer = "ExampleServer", //令牌发行者 ValidAudience = "ExampleClients", //令牌受众 IssuerSigningKey = SecurityKey, //密钥 }; }); }
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapGrpcService<TicketerService>(); endpoints.MapGet("/generateJwtToken", context => { return context.Response.WriteAsync(GenerateJwtToken(context.Request.Query["name"])); }); }); }
//这里是生成token的代码,当然正常逻辑这里会增加用户密码验证,并做一些权限角色处理 //如正常登录后权限角色写入到redis ,重写 Authorize 特性增加权限验证逻辑 private string GenerateJwtToken(string name) { if (string.IsNullOrEmpty(name)) { throw new InvalidOperationException("Name is not specified."); } var claims = new[] { new Claim(ClaimTypes.Name, name) }; var credentials = new SigningCredentials(SecurityKey, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken("ExampleServer", "ExampleClients", claims, expires: DateTime.Now.AddSeconds(60), signingCredentials: credentials); return JwtTokenHandler.WriteToken(token); }
客户端调用代码示例:
//登录验证并得到token private static async Task<string> Authenticate() { Console.WriteLine($"Authenticating as {Environment.UserName}..."); var httpClient = new HttpClient(); var request = new HttpRequestMessage { RequestUri = new Uri($"{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("Successfully authenticated."); return token; }
//调用服务端接口,并加入验证token private static async Task PurchaseTicket(Ticketer.TicketerClient client, string? token) { Console.WriteLine("Purchasing ticket..."); try { Metadata? headers = null; if (token != null) { headers = new Metadata(); headers.Add("Authorization", $"Bearer {token}"); headers.Add("alg", "HS256"); //加密方式 } var response = await client.BuyTicketsAsync(new BuyTicketsRequest { Count = 1 }, headers); 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()); } }
//服务端代码示例,这里增加 Authorize 特性表示需要验证 //Authorize 的验证规则与验证代理已经在 ConfigureServices 函数配置好。 [Authorize] public override Task<BuyTicketsResponse> BuyTickets(BuyTicketsRequest request, ServerCallContext context) { var user = context.GetHttpContext().User; return Task.FromResult(new BuyTicketsResponse { Success = _ticketRepository.BuyTickets(user.Identity.Name!, request.Count) }); }
参考:https://www.cnblogs.com/7tiny/archive/2019/06/13/11012035.html
https://cloud.tencent.com/developer/ask/130481