学习设计微服务:api认证

  • A+
所属分类:.NET技术
摘要

前言
最近再学习微服务,所以把自己的个人站点https://www.ttblog.site/拆分成微服务。目前正在思考微服务里面的认证与授权,网上百度到都是根据用户名和密码来实现的,考虑到实际的原因,我的个人站点是最先访问不需要登录,当执行写入或更改操作时才需要用户名和密码,所以我自己思考了一个方案,这里分享一下,设计难免有很多不合理之处,大家可以予以批评。
文档
我开始做的时候,对认证授权不是很理解,所以我在网上百度并且在博客园和开源中国提了一下问。https://www.oschina.net/question/2859520_2319077和https://q.cnblogs.com/q/129422/。并且看了很多文章,大多数使用的是IdentityServer4,但是我发现这个比较复杂,貌似还要安装一些认证,所以选择了使用JWT。并且了解了一下OAuth2,我觉得我用的应该属于里面的客户端模式https://www.jianshu.com/p/84a4b4a1e833。大概都了解之后,我就开始在项目里集成了jwt和ocelot。
实战
首先创建了一个认证服务器
BlogAuthApi
然后一个网关
BlogGateway
最后一个
BlogWebApi
我的思路就是js判断是否存有token,如果没有在请求认证服务器Auth,,返回一个token,存入浏览器,然后之后通过token去访问webapi。
1,请求token
我这里使用的微服务网关属于Ocelot,请求时通过网关转发到认证服务器获取token,如下代码生成token:

前言
最近再学习微服务,所以把自己的个人站点https://www.ttblog.site/拆分成微服务。目前正在思考微服务里面的认证与授权,网上百度到都是根据用户名和密码来实现的,考虑到实际的原因,我的个人站点是最先访问不需要登录,当执行写入或更改操作时才需要用户名和密码,所以我自己思考了一个方案,这里分享一下,设计难免有很多不合理之处,大家可以予以批评。
文档
我开始做的时候,对认证授权不是很理解,所以我在网上百度并且在博客园和开源中国提了一下问。https://www.oschina.net/question/2859520_2319077https://q.cnblogs.com/q/129422/。并且看了很多文章,大多数使用的是IdentityServer4,但是我发现这个比较复杂,貌似还要安装一些认证,所以选择了使用JWT。并且了解了一下OAuth2,我觉得我用的应该属于里面的客户端模式https://www.jianshu.com/p/84a4b4a1e833。大概都了解之后,我就开始在项目里集成了jwt和ocelot。
实战
首先创建了一个认证服务器
BlogAuthApi
然后一个网关
BlogGateway
最后一个
BlogWebApi
我的思路就是js判断是否存有token,如果没有在请求认证服务器Auth,,返回一个token,存入浏览器,然后之后通过token去访问webapi。
1,请求token
我这里使用的微服务网关属于Ocelot,请求时通过网关转发到认证服务器获取token,如下代码生成token:

 public class Jwt     {         /// <summary>         /// 返回jwt模型         /// </summary>         /// <returns></returns>         public static JwtOption GetOption()         {             JwtOption option = ConfigureProvider.BuildModel<JwtOption>("jwtOption");             return option;         }         /// <summary>         ///  返回SymmetricSecurityKey         /// </summary>         /// <returns></returns>         public static SymmetricSecurityKey GetSymmetricSecurityKey()         {             JwtOption option = GetOption();             return GetSymmetricSecurityKey(option.Secret);         }         /// <summary>         ///  返回SymmetricSecurityKey         /// </summary>         /// <returns></returns>         public static SymmetricSecurityKey GetSymmetricSecurityKey(string secret)         {             return new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));         }         /// <summary>         /// 返回token参数模型         /// </summary>         /// <returns></returns>         public static TokenValidationParameters GetTokenValidation()         {             JwtOption option = GetOption();             var tokenValidationParameters = new TokenValidationParameters             {                 ValidateIssuerSigningKey = true,                 IssuerSigningKey = GetSymmetricSecurityKey(option.Secret),                 ValidateIssuer = true,                 ValidIssuer = option.Issuer,                 ValidateAudience = true,                 ValidAudience = option.Audience,                 ValidateLifetime = true,                 ClockSkew = TimeSpan.Zero,                 RequireExpirationTime = true,              };             return tokenValidationParameters;         }         /// <summary>         /// 获取jwt的token参数         /// </summary>         /// <param name="claims"></param>         /// <returns></returns>         public static JwtSecurityToken GetJwtParameters(Claim[] claims,JwtOption option=null)         {             if (option == null)                 option = GetOption();             var jwt = new JwtSecurityToken(                issuer: option.Issuer,                audience: option.Audience,                claims: claims,                notBefore: DateTime.Now,                expires: DateTime.Now.Add(TimeSpan.FromMinutes(option.ExpireMinutes)),                signingCredentials: new SigningCredentials(GetSymmetricSecurityKey(option.Secret), SecurityAlgorithms.HmacSha256)             );             return jwt;         }         /// <summary>         /// 获取jwt         /// </summary>         /// <param name="claims"></param>         /// <returns></returns>         public static JwtToken GetToken(JwtSecurityToken tokenParameters)         {             JwtOption option = GetOption();             string token=new JwtSecurityTokenHandler().WriteToken(tokenParameters);             return new JwtToken(token, option.ExpireMinutes);         }         /// <summary>         /// 获取jwt         /// </summary>         /// <param name="claims"></param>         /// <returns></returns>         public static JwtToken GetToken(Claim[] claims)         {             JwtOption option = GetOption();             JwtSecurityToken jwtSecurityToken = GetJwtParameters(claims,option);             string token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);             return new JwtToken(token, option.ExpireMinutes*60);         }     }      public class JwtToken     {         public string Token { get; set; }         public int ExpireSeconds { get; set; }         public JwtToken(string token,int expireSeconds)         {             Token = token;             ExpireSeconds = expireSeconds;         }     }   public class JwtOption     {         public string Issuer { get; set; }         public string Audience { get; set; }         public int ExpireMinutes { get; set; }         public string Secret { get; set; }     } 

  

 

学习设计微服务:api认证

并且添加配置文件

 "jwtOption": {     "issuer": "",     "audience": "",     "expireMinutes": "",     "secret": ""   }

学习设计微服务:api认证

然后前端获取到token之后会吧token放入到header里面请求。
2,配置网关服务Ocelot
使用ocelot认证时,需要配置Ocelot.json,对相应的路由添加节点

 {       "DownstreamPathTemplate": "/api/{url}",       "DownstreamScheme": "http",       "DownstreamHostAndPorts": [         {           "Host": "localhost",           "Port": 5001         }       ],       "UpstreamPathTemplate": "/{url}",       "UpstreamHttpMethod": [ "Get", "Post", "Delete" ],       "AuthenticationOptions": {         "AuthenticationProviderKey": "ApiAuthKey",//认证服务的key         "AllowedScopes": []       },       //限流       "RateLimitOptions": {         "ClientWhitelist": [],         "EnableRateLimiting": true,         "Period": "1s",         "PeriodTimespan": 1,         "Limit": 1       }     } 

  

学习设计微服务:api认证

让后需要在Startup里面添加Jwt如下:

  services.AddAuthentication()              .AddJwtBearer("ApiAuthKey", x =>              {                  x.RequireHttpsMetadata = false;                  x.TokenValidationParameters = tokenValidationParameters;                              }); 

  

学习设计微服务:api认证

之后启动3个服务来测试下,
当我们不传token时,请求时直接返回401的:
学习设计微服务:api认证
然后我们请求认证服务器获取token
学习设计微服务:api认证
然后我们把token放入header里面请求:
学习设计微服务:api认证
可以看到请求成功了,并且我们可以看到token的过期时间为120秒,然后过了两分钟我们在请求就不行了
学习设计微服务:api认证
到此,我的api认证功能已经大致完成了,因为自己并没有这方面的经验,例如怎么token过期了前端怎么取刷新的问题,怎么扩展ocelot过期返回的response等等,自己都是要一点一点去学习了解的,这里只是贴出我的过程,和大家分享讨论下,希望可以给出好的意见。