身份认证用于登陆认证、授权等作用,下面将展示如何在gRPC中进行身份认证
一、服务端添加身份认证
1. 添加Nuget包
工具 > Nuget包管理器 > 程序包管理控制台 > 设置默认项目为GrpcDemo.Service
输入以下命令:
Install-Package Microsoft.AspNetCore.Authentication.JwtBearer -v 3.1.14
2. 添加身份认证
修改 GrpcDemo.Service > Startup.cs
public void ConfigureServices(IServiceCollection services)
{
//注册身份认证服务
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
//使用Jwt认证
.AddJwtBearer(o =>
{
o.TokenValidationParameters = new TokenValidationParameters()
{
ValidIssuer = "jwttest",
ValidAudience = "jwttest",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("hello_worldhello_worldhello_worldhello_world")),
};
});
//注册授权服务
services.AddAuthorization();
//...省略
}
3. 添加Proto文件
在 GrpcDemo.Service\Protos 添加一个proto文件,命名为auth.proto
添加以下内容:
syntax = "proto3";
option csharp_namespace = "GrpcDemo.Service";
package auth;
// The greeting service definition.
service Auth {
// Sends a greeting
rpc GetToken (AuthData) returns (AuthResult);
rpc Test(Empty) returns (Empty);
}
// The request message containing the user's name.
message AuthData {
string name = 1;
string pass = 2;
}
// The response message containing the greetings.
message AuthResult {
int32 code = 1;
string token = 2;
string message = 3;
}
message Empty{}
该文件声明了一个Auth服务,包含GetToken、Test方法以及传输对象数据结构。
修改GrpcDemo.Service项目文件:
<!-- 将 greet.proto 替换为 *.proto -->
<Protobuf Include="Protos\*.proto" GrpcServices="Server" />
注意:在添加proto文件后,客户端需重新生成项目,生成proto声明的类
4. 添加服务实现
在 GrpcDemo.Service\Services 添加AuthService.cs类,继承于生成的Auth.AuthBase
添加以下内容:
//重写GetToken编写认证逻辑
public override Task<AuthResult> GetToken(AuthData request, ServerCallContext context)
{
if (request.Name == "alice" && request.Pass == "alice")
{
var claims = new[] {
new Claim(ClaimTypes.Name, "alice"),
new Claim(ClaimTypes.NameIdentifier, "0")
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("hello_worldhello_worldhello_worldhello_world"));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: "jwttest",
audience: "jwttest",
claims: claims,
notBefore: DateTime.UtcNow,
expires: DateTime.UtcNow.AddSeconds(10),
signingCredentials: creds);
var stoken = new JwtSecurityTokenHandler().WriteToken(token);
return Task.FromResult(new AuthResult()
{
Code = 1,
Message = "success",
Token = stoken
});
}
return Task.FromResult(new AuthResult()
{
Code = -1,
Message = "用户名或密码错误"
});
}
//添加Authorize测试认证
[Authorize]
public override Task<Empty> Test(Empty request, ServerCallContext context)
{
var user = context.GetHttpContext().User;
Console.WriteLine(user.Identity.Name);
return Task.FromResult(new Empty());
}
5. 注册授权服务并添加认证
修改 GrpcDemo.Service > Startup.cs
public void ConfigureServices(IServiceCollection services)
{
//注册身份认证服务
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
//使用Jwt认证
.AddJwtBearer(o =>
{
o.TokenValidationParameters = new TokenValidationParameters()
{
ValidIssuer = "jwttest",
ValidAudience = "jwttest",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("hello_worldhello_worldhello_worldhello_world")),
};
});
//注册授权服务
services.AddAuthorization();
services.AddGrpc();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//...省略
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<GreeterService>();
//添加授权服务
endpoints.MapGrpcService<AuthService>();
//...省略
});
}
二、客户端获取Token认证
修改 GrpcDemo.Clint > Program.cs > Main
class Program
{
private const string ServiceAddress = "https://localhost:5001";
static void Main(string[] args)
{
var channel = GetAuthGrpcChannel();
var task = AuthTest(channel);
task.Wait();
}
/// <summary>
/// 获取已身份认证的GrpcChannel
/// </summary>
public static GrpcChannel GetAuthGrpcChannel()
{
var channel = GrpcChannel.ForAddress(ServiceAddress);
var authClient = new Auth.AuthClient(channel);
//获取Token
var token = authClient.GetToken(new AuthData()
{
Name = "alice",
Pass = "alice"
});
channel.Dispose();
//创建Authorization证书
var credentials = CallCredentials.FromInterceptor((context, metadata) =>
{
if (!string.IsNullOrEmpty(token.Token))
{
metadata.Add("Authorization", $"Bearer {token.Token}");
}
return Task.CompletedTask;
});
//创建具有Token的通道
var auth_channel = GrpcChannel.ForAddress(ServiceAddress, new GrpcChannelOptions()
{
Credentials = ChannelCredentials.Create(new SslCredentials(), credentials)
});
return auth_channel;
}
/// <summary>
/// 测试身份认证
/// </summary>
/// <param name="invoker"></param>
/// <returns></returns>
public static async Task AuthTest(GrpcChannel channel)
{
Console.WriteLine("AuthTest");
var authClient = new Auth.AuthClient(channel);
await authClient.TestAsync(new Empty());
Console.WriteLine("AuthSuccess");
}
}
GetAuthGrpcChannel获取已认证的RrpcChannel,调用该通道运行AuthTest方法
三、运行并查看结果
输出: