IdentityServer4 负载均衡配置

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

  在不用到负载之前,一切都很好,但是部署多个实例之后,问题挺多的:session问题、令牌签发后的校验问题。

  在不用到负载之前,一切都很好,但是部署多个实例之后,问题挺多的:session问题、令牌签发后的校验问题。

在此之前,先自查官方文档:Deployment — IdentityServer4 1.0.0 documentation

把必要的东西都配置正确,然后继续排查。

session问题

   在需要经常需要与统一身份认证平台进行交互的情况(比如,A站点和B站点都是统一身份认证平台下的子系统,希望A站点登录后,在B进行登录的时候可以免登录的情形),建议不用继续使用sessionID,如果不需要,则存放在redis,实现分布式session也是选择。

令牌签发后的校验问题

  部署后启动:

2021-11-01 12:01:50.098 [WRN] Using an in-memory repository. Keys will not be persisted to storage

然后在A站点登录之后,关闭A站点,启动B站点进行测试是否正常可以验证通过,会发现提示去登录,查看日志发现:

2021-11-01 12:01:50.276 [ERR] cookie Showing login: User is not authenticated

然后F12查看cookie已经被删除,讲白了就是AB两个站点并不互认,官方文档里面写着

IdentityServer itself is stateless and does not require server affinity - but there is data that needs to be shared between the instances.

我真想抽它鸭子的。

解决:

  因为ids4是有引用到微软库的一个 Microsoft.AspNetCore.DataProtection ,所以可以不用引用,你需要引用一个包:

Microsoft.AspNetCore.DataProtection.StackExchangeRedis

然后在使用:

var redis = ConnectionMultiplexer.Connect( Configuration["Redis:HostPort"]); services.AddDataProtection()
.SetApplicationName(Configuration[
"Redis:ApplicationName"]) .PersistKeysToStackExchangeRedis( redis, "DataProtection-Keys");

就ok了,或者不想用StackExchangeRedis,就自己实现:

 public class CustomRedisXmlRepository : Microsoft.AspNetCore.DataProtection.Repositories.IXmlRepository     {         protected readonly IRedisCache redisCache;         protected readonly int DBIndex;         private readonly string key;          public CustomRedisXmlRepository(IRedisCache redisCache, int dbIndex, string key)         {             this.redisCache = redisCache;             this.DBIndex = dbIndex;             this.key = key;         }          /// <inheritdoc />         public IReadOnlyCollection<XElement> GetAllElements()         {             return GetAllElementsCore().ToList().AsReadOnly();         }          private IEnumerable<XElement> GetAllElementsCore()         {             foreach (var value in redisCache.GetList<string>(DBIndex,key))             {                 yield return XElement.Parse(value);             }         }          public void StoreElement(XElement element, string friendlyName)         {              redisCache.AddList(DBIndex,key, element.ToString(SaveOptions.DisableFormatting));         }     }

扩展:

public static class RedisDataProtectionBuilderExtensions     {         private const string DataProtectionKeysName = "DataProtection-Keys";         private const int DefaultDBIndex = 0;          public static IDataProtectionBuilder PersistKeysToRedis(this IDataProtectionBuilder builder, IRedisCache redisCache,int dbIndex, string key)         {             if (builder == null)             {                 throw new ArgumentNullException(nameof(builder));             }             if (redisCache == null)             {                 throw new ArgumentNullException(nameof(IRedisCache));             }             return PersistKeysToRedisInternal(builder, redisCache, dbIndex, key);         }          public static IDataProtectionBuilder PersistKeysToRedis(this IDataProtectionBuilder builder, IRedisCache redisCache)         {             return PersistKeysToRedis(builder, redisCache, DefaultDBIndex, DataProtectionKeysName);         }          private static IDataProtectionBuilder PersistKeysToRedisInternal(IDataProtectionBuilder builder, IRedisCache redisCache, int dbIndex, string key)         {             builder.Services.Configure<KeyManagementOptions>(options =>             {                 options.XmlRepository = new CustomRedisXmlRepository(redisCache, dbIndex, key);             });             return builder;         }     }

引用

 var redis = services.BuildServiceProvider().GetService<IRedisCache>();   services.AddDataProtection()          .SetApplicationName(config.RedisOptions.KeyPrefix+ "-Identityserver4-Production-Key")          .PersistKeysToRedis(redis, Application.Configs.RedisKey.Application, config.RedisOptions.KeyPrefix + "-DataProtection-Keys");

然后重新测试,会发现token已经校验通过:

2021-11-01 12:02:04.515 [INF] Token request validation success, {"ClientId":"zhicheng","ClientName":"**","GrantType":"authorization_code","Scopes":null,"AuthorizationCode":"****93B3","RefreshToken":"********","UserName":null,"AuthenticationContextReferenceClasses":null,"Tenant":null,"IdP":null,"Raw":{"client_id":"***","client_secret":"***REDACTED***","grant_type":"authorization_code","code":"153AF90A4B84AC5C0C8ABA1E22483A05936B6009E123AA8937015F26FD6A93B3","redirect_uri":"http://localhost:6001/Home/Index"},"$type":"TokenRequestValidationLog"}  

坐等下班!