.Net gRPC使用Jwt验证详细教程

继上一篇文章 玩转.Net gRPC简单使用详细教程

首先在服务端 定义获取身份验证Token方法,在Message.proto文件

message TokenRequest{
	string username = 1;
	string password = 2;
}

message TokenResponse{
	string token = 1;
	google.protobuf.Timestamp expiration = 2;
	bool success = 3;
}

service EmployeeService{
	rpc GetByNo(GetByNoRequest) returns (EmployeeResponse);
	rpc GetAll(GetAllRequest) returns (stream EmployeeResponse);
	rpc AddPhoto(stream AddPhotoRequest) returns (AddPhotoResponse);

	rpc Save(EmployeeRequest) returns (EmployeeResponse);
	rpc SaveAll(stream EmployeeRequest) returns (stream EmployeeResponse);
	rpc CreateToken(TokenRequest)  returns (TokenResponse);
}

安装Nuget包 Microsoft.AspNetCore.Authentication.JwtBearer

StartUp.cs中:

 public void ConfigureServices(IServiceCollection services)
        {
            services.AddScoped<JwtTokenValidationService>();
            services.AddGrpc();
            services.AddAuthorization();
            services.AddAuthentication()
                .AddJwtBearer(options=> { 
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuer = true,//是否验证Issuer
                        ValidateAudience = true,//是否验证Audience
                        ValidateLifetime = true,//是否验证失效时间
                        ClockSkew = TimeSpan.FromSeconds(30),
                        ValidateIssuerSigningKey = true,//是否验证SecurityKey
                        ValidIssuer = "localhost",
                        ValidAudience = "localhost",
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("wef1561fwffwef5q1wd51z117wqd05f8ewgt515qwd"))
                    };

                });
        }

            app.UseRouting();
            app.UseHttpsRedirection();

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGrpcService<MyEmployeeService>();
            });

接着创建服务 JwtTokenValidationService.cs

using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

namespace GrpcServer.Web.Services
{
    public class TokenModel
    {
        public string Token { get; set; }
        public DateTime Expiration { get; set; }
        public bool Sucess { get; set; }
    }
    public class UserModel
    {
        public string UserName { get; set; }
        public string PassWord { get; set; }
    }

    public class JwtTokenValidationService
    {
        public async Task<TokenModel> GenerateTokenAsync(UserModel model)
        {
            if (model.UserName == "admin" && model.PassWord == "123456")
            {
                var claims = new[]
                {
                    new Claim(JwtRegisteredClaimNames.Sub,"email@126.com"),
                    new Claim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString()),
                    new Claim(JwtRegisteredClaimNames.UniqueName,"admin")
                };

                var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("wef1561fwffwef5q1wd51z117wqd05f8ewgt515qwd"));
                var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

                var token = new JwtSecurityToken(
                    "localhost",// Issuer 颁发者,通常为STS服务器地址
                    "localhost",// Audience Token的作用对象,也就是被访问的资源服务器授权标识
                    claims,
                    DateTime.Now,  //Token生效时间,在此之前不可用
                    DateTime.Now.AddMinutes(30), //Token过期时间,在此之后不可用
                    creds);
                return new TokenModel
                {
                    Token = new JwtSecurityTokenHandler().WriteToken(token),
                    Expiration  = token.ValidTo,
                    Sucess = true
                };
            }
            return new TokenModel
            {
                Sucess = false
            };
           
        }
    }
}

在MyEmployeeService.cs中实现验证方法:

[Authorize(AuthenticationSchemes =JwtBearerDefaults.AuthenticationScheme)]
public class MyEmployeeService : EmployeeServiceBase{

private readonly ILogger<MyEmployeeService> logger;
        private readonly JwtTokenValidationService jwtTokenValidationService;

        public MyEmployeeService(ILogger<MyEmployeeService> logger,
            JwtTokenValidationService jwtTokenValidationService)
        {
            this.logger = logger;
            this.jwtTokenValidationService = jwtTokenValidationService;
        }

        [AllowAnonymous]
        public override async Task<TokenResponse> CreateToken(TokenRequest request, ServerCallContext context)
        {
            var userModel = new UserModel
            {
                UserName = request.Username,
                PassWord = request.Password
            };
            var response = await jwtTokenValidationService.GenerateTokenAsync(userModel);
            if (response.Sucess)
            {
                return new TokenResponse
                {
                    Token = response.Token,
                    Expiration = Timestamp.FromDateTime(response.Expiration),
                    Success = true
                };
            }
            return new TokenResponse
            {
                Success = false
            };
        }



}

服务端就写完了,先运行起来。

接下来是客户端:

定义两个变量

private static string _token;
private static DateTime _expiration = DateTime.MinValue;

实现验证方法如下:

        private static bool NeedToken() => string.IsNullOrEmpty(_token) || _expiration > DateTime.UtcNow;


        public static async Task GetByNoAsync(EmployeeService.EmployeeServiceClient client)
        {
           
            if (!NeedToken()|| await GetTokenAsync(client))
            {
                var headers = new Metadata
                {
                    {"Authorization",$"Bearer {_token}" }
                };
                var response = await client.GetByNoAsync(new GetByNoRequest()
                {
                    No = 1994
                }, headers);

                Console.WriteLine(response);
            }
            
        }


        private static async Task<bool> GetTokenAsync(EmployeeService.EmployeeServiceClient client)
        {
            var request = new TokenRequest
            {
                 Username = "admin", Password = "123456"
            };
            var response = await client.CreateTokenAsync(request);
            if (response.Success)
            {
                _token = response.Token;
                _expiration = response.Expiration.ToDateTime();
                return true;
            }
            return false;
        }

 

接着运行dotnet run 1