2020年9月30日星期三

学习设计微服务:api认证 - 灬丶 - 开发者的网上家园

前言
最近再学习微服务,所以把自己的个人站点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:

 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; } }

  

 

并且添加配置文件

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

然后前端获取到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  } }

  

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

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

  

之后启动3个服务来测试下,
当我们不传token时,请求时直接返回401的:

然后我们请求认证服务器获取token

然后我们把token放入header里面请求:

可以看到请求成功了,并且我们可以看到token的过期时间为120秒,然后过了两分钟我们在请求就不行了

到此,我的api认证功能已经大致完成了,因为自己并没有这方面的经验,例如怎么token过期了前端怎么取刷新的问题,怎么扩展ocelot过期返回的response等等,自己都是要一点一点去学习了解的,这里只是贴出我的过程,和大家分享讨论下,希望可以给出好的意见。

原文转载:http://www.shaoqun.com/a/478797.html

ebay易趣:https://www.ikjzd.com/w/210

沃尔码:https://www.ikjzd.com/w/220

c88是什么:https://www.ikjzd.com/w/1017


前言最近再学习微服务,所以把自己的个人站点https://www.ttblog.site/拆分成微服务。目前正在思考微服务里面的认证与授权,网上百度到都是根据用户名和密码来实现的,考虑到实际的原因,我的个人站点是最先访问不需要登录,当执行写入或更改操作时才需要用户名和密码,所以我自己思考了一个方案,这里分享一下,设计难免有很多不合理之处,大家可以予以批评。文档我开始做的时候,对认证授权不是很理解,
blackbird:https://www.ikjzd.com/w/950
modcloth:https://www.ikjzd.com/w/1271
利润高达25%!选品新机会点来了!:https://www.ikjzd.com/home/123522
联邦快递公司承运来华快递涉枪,怎么又是你? :https://www.ikjzd.com/home/104845
Giveaway中文版:https://www.ikjzd.com/tl/102229