我如何让2个身份服务器客户端共享刷新令牌,但是使用差异RefreshTokenUsage
我们正在尝试将QR码登录流程添加到我们的系统中
假设后端包含3个项目:Identity-Server,API-Server,SignalR-Hub-Server
API-Server从Identity-Server获取Jwt和RefreshToken之后,授权的API端点将负责将RefreshToken发送到SignalR-Hub-Server以获取新的令牌集并发出前端连接登录信号。
问题是我使用API登录并使用刷新令牌从集线器获取新令牌后,Identity Server返回错误消息
HubServer尝试刷新属于ApiServer的令牌
我们的API服务器具有刷新令牌端点,因此RefreshTokenUsage
应该是OneTime
但是,当我们使用该令牌从SignalR-Hub-Server获取新的登录会话时,我们希望刷新而不撤消原始令牌(因为QR登录是要使用现有登录名创建一个新部分),所以我希望RefreshTokenUsage
成为ReUse
我目前在Identity-Server项目中拥有什么
API服务器,SignalR-Hub服务器之间的连接已正确设置
Startup.cs
public class Startup
{
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
=> Configuration = configuration;
public void ConfigureServices(IServiceCollection services)
{
services
.AddTransient<IIdentityRepository, IdentityRepository>(x => new IdentityRepository(Configuration.GetConnectionString("db")))
.AddTransient<IRefreshTokenRepository, RefreshTokenRepository>(x => new RefreshTokenRepository(Configuration.GetConnectionString("db")))
.AddTransient<IAuthenticatorFactory, AuthenticatorFactory>()
.AddTransient<IRefreshTokenStore, CustomRefreshTokenStore>();
services
.AddIdentityServer()
.AddInMemoryApiResources(InMemoryConfiguration.ApiResources())
.AddInMemoryClients(InMemoryConfiguration.Clients(Configuration))
.AddResourceOwnerValidator<ResourceOwnerPasswordValidator>();
services
.AddHealthChecks()
.AddSqlServer(
Configuration.GetConnectionString("db"),
name: "db");
services.AddMvc();
}
public void ConfigureContainer(ContainerBuilder builder)
=> builder.RegisterAssemblyTypes(typeof(IAuthenticationProvider).Assembly)
.Where(t => t.IsAssignableTo<IAuthenticationProvider>())
.AsImplementedInterfaces();
public void Configure(IApplicationBuilder app)
=> app.UseIdentityServer();
}
InMemoryConfiguration.cs
public static class InMemoryConfiguration
{
public static IEnumerable<ApiResource> ApiResources() => new[]
{
new ApiResource("ApiServer", "API Server")
{
UserClaims = new[]
{
JwtRegisteredClaimNames.Jti,
JwtRegisteredClaimNames.Iat,
ClaimTypes.Name,
ClaimTypes.Email
}
},
new ApiResource("HubServer", "SignalR Hub")
{
UserClaims = new[]
{
JwtRegisteredClaimNames.Jti,
JwtRegisteredClaimNames.Iat,
ClaimTypes.Name,
ClaimTypes.Email
}
}
};
public static IEnumerable<Client> Clients(IConfiguration configuration) => new[]
{
new Client
{
ClientId = configuration.GetValue<string>("Client:ApiServer:Id"),
ClientSecrets =
{
new Secret(configuration.GetValue<string>("Client:ApiServer:Secret").Sha256())
},
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OfflineAccess,
configuration.GetValue<string>("Client:ApiServer:Id"),
configuration.GetValue<string>("Client:HubServer:Id")
},
AllowOfflineAccess = true,
AccessTokenLifetime = configuration.GetValue<int>("JwtLifeTime"),
RefreshTokenExpiration = TokenExpiration.Absolute,
AbsoluteRefreshTokenLifetime = configuration.GetValue<int>("RefreshTokenLifeTime"),
},
new Client
{
ClientId = configuration.GetValue<string>("Client:HubServer:Id"),
ClientSecrets =
{
new Secret(configuration.GetValue<string>("Client:HubServer:Secret").Sha256())
},
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OfflineAccess,
configuration.GetValue<string>("Client:ApiServer:Id"),
configuration.GetValue<string>("Client:HubServer:Id")
},
AllowOfflineAccess = true,
RefreshTokenUsage = ReUse // <---- This is the only difference between the 2 clients
AccessTokenLifetime = configuration.GetValue<int>("JwtLifeTime"),
RefreshTokenExpiration = TokenExpiration.Absolute,
AbsoluteRefreshTokenLifetime = configuration.GetValue<int>("RefreshTokenLifeTime"),
}
};
}