Servicestack导致承载令牌无效

Posted

技术标签:

【中文标题】Servicestack导致承载令牌无效【英文标题】:Servicestack causing invalidated the bearer token 【发布时间】:2020-03-09 16:14:05 【问题描述】:

我们有一个被 Angular 网站访问的 ServiceStack 服务。随机且我们无法确定它发生的原因或时间,不记名令牌正在失效。我们可以看到不记名令牌不被接受并出现错误消息。 “令牌已失效”。我确定我们没有重新启动 servicestack 服务,并且我们仍然在请求中传递原始不记名令牌。我们没有实现任何逻辑来使不记名令牌无效。我知道这有点模糊。如果有人可以指出如何在 ServiceStack 中解决这个问题。这就是我需要的。

使用 servicestack 5.4.1

namespace cbw.mvc.web.service


    public class AppHost : AppHostBase
    
        public AppHost() : base("ServiceStack + .NET Core", typeof(StartupService).Assembly)  

        public override void Configure(Funq.Container container)
        
            Plugins.Add(new SwaggerFeature());

            Plugins.Add(new RazorFormat());

            //Works but recommend handling 404 at end of .NET Core pipeline
            //this.CustomErrorHttpHandlers[HttpStatusCode.NotFound] = new RazorHandler("/notfound");
            this.CustomErrorHttpHandlers[HttpStatusCode.Unauthorized] = new RazorHandler("/login");

            //To include null values in the json globally
            JsConfig.IncludeNullValues = true;
            //This is mandate. We need "IncludeNullValuesInDictionaries = true" to include null values
            JsConfig.IncludeNullValuesInDictionaries = true;


            var corsWhitelist = AppSettings.GetList("cors.whitelist.urls");

            //To automatically wired up for you on all HTTP Verbs (GET, POST, etc) 
            //And built-in endpoints, i.e. DeviceConfigValues, XML, JSV, html, CSV, SOAP
            Plugins.Add(new CorsFeature(
                allowOriginWhitelist: corsWhitelist,
                allowCredentials: true,
                allowedHeaders: "Content-Type, Allow, Authorization,UserId,CompanyId"));

            //To add registration feature
            Plugins.Add(new RegistrationFeature());

            //To add validation feature
            Plugins.Add(new ValidationFeature());
            container.RegisterValidators(
                typeof(InsertCompanyValidator).Assembly,
                typeof(UpdateCompanyValidator).Assembly,
                typeof(DeleteCompanyValidator).Assembly,

                typeof(InsertDeviceTypeValidator).Assembly,
                typeof(UpdateDeviceTypeValidator).Assembly,
                typeof(DeleteDeviceTypeValidator).Assembly,

                typeof(InsertLocationValidator).Assembly,
                typeof(UpdateLocationValidator).Assembly,
                typeof(DeleteLocationValidator).Assembly,

                //typeof(InsertRolePermissionValidator).Assembly,
                //typeof(UpdateRolePermissionValidator).Assembly,

                //Page Validator
                typeof(AddSecPageValidator).Assembly,
                typeof(UpdateSecPageValidator).Assembly,
                typeof(DeleteSecPageValidator).Assembly,

                //Page Permission Validator
                typeof(AddPagePermissionValidator).Assembly,
                typeof(UpdatePagePermissionValidator).Assembly,

                //SecGroup Validator
                typeof(AddSecGroupValidator).Assembly,
                typeof(UpdateSecGroupValidator).Assembly,
                typeof(DeleteSecGroupValidator).Assembly,

                //GroupRole Validator
                typeof(AddGroupRoleValidator).Assembly,
                typeof(UpdateGroupRoleValidator).Assembly,
                typeof(DeleteGroupRoleValidator).Assembly,

                //UserGroup Validator
                typeof(AddUserGroupValidator).Assembly,
                typeof(UpdateUserGroupValidator).Assembly,
                typeof(DeleteUserGroupValidator).Assembly,

                //GroupCompany Validator
                typeof(AddGroupCompanyValidator).Assembly,
                typeof(UpdateGroupCompanyValidator).Assembly,
                typeof(DeleteGroupCompanyValidator).Assembly,

                //Document Validator
                typeof(AddDocumentValidator).Assembly,
                typeof(UpdateDocumentValidator).Assembly,
                typeof(DeleteDocumentValidator).Assembly,

                //DocumentType Validator
                typeof(AddDocumentTypeValidator).Assembly,
                typeof(UpdateDocumentValidator).Assembly,
                typeof(DeleteDocumentValidator).Assembly,

                 // iosetup Validator
                 typeof(DeviceIOSetupLocalDigitalInputAddValidator).Assembly,
                 typeof(DeviceIOSetupRemoteDigitalInputAddValidator).Assembly,
                 typeof(DeviceIOSetupExpansionDigitalInputAddValidator).Assembly,
                 typeof(DeviceIOSetupLocalRelayAddValidator).Assembly,
                 typeof(DeviceIOSetupRemoteRelayAddValidator).Assembly,
                 typeof(DeviceIOSetupExpansionRelayAddValidator).Assembly,
                 typeof(DeviceIOSetupRemoteAnalogOutputAddValidator).Assembly,
                 typeof(DeviceIOSetupLocalAnalogInputAddValidator).Assembly,
                 typeof(DeviceIOSetupRemoteAnalogInputAddValidator).Assembly,
                 typeof(DeviceIOSetupExpansionAnalogInputAddValidator).Assembly,
                 typeof(DeviceIOSetupLocalDigitalIOAddValidator).Assembly,
                 typeof(DeviceIOSetupRemoteDigitalIOAddValidator).Assembly,
                 typeof(DeviceIOSetupLocalOneWireAddValidator).Assembly,
                 typeof(DeviceIOSetupRemoteOneWireAddValidator).Assembly,
                 typeof(DeviceIOSetupRemoteThermocoupleAddValidator).Assembly,
                 typeof(DeviceIOSetupExpansionThermocoupleAddValidator).Assembly,
                 typeof(DeviceIOSetupLocalRegisterAddValidator).Assembly,
                 typeof(DeviceIOSetupRemoteRegisterAddValidator).Assembly,
                 typeof(DeviceIOSetupLocalVinAddValidator).Assembly,
                 typeof(DeviceIOSetupRemoteVinAddValidator).Assembly,
                 typeof(DeviceIOSetupLocalTimerAddValidator).Assembly,
                 typeof(DeviceIOSetupRemoteBatteryAddValidator).Assembly,
                 typeof(DeviceIOSetupLocalFrequencyInputAddValidator).Assembly,
                 typeof(DeviceIOSetupRemoteFrequencyInputAddValidator).Assembly
            );

            Plugins.Add(new AuthFeature(() => new CustomUserSession(),
                new IAuthProvider[]
                
                    //new BasicAuthProvider(),                    //Sign-in with HTTP Basic Auth
                    new JwtAuthProvider(AppSettings) 
                        //HashAlgorithm = "HM256",
                        //PrivateKey = privateKey.ExportParameters(true),
                        AuthKeyBase64 = AppSettings.GetString("jwt.auth.key"),
                        RequireSecureConnection = false,
                        InvalidateTokensIssuedBefore = DateTime.Now,
                        ExpireTokensIn = TimeSpan.FromHours(24)
                        //Turn on for Prod: EncryptPayload = true
                        , //JWT TOKENS
                    new CredentialsAuthProvider(AppSettings)
                )
            
                HtmlRedirect = "/",
                //IncludeRegistrationService = true,
            );

            //Permit modern browsers (e.g. Firefox) to allow sending of any HTTP Method
            //SetConfig(new HostConfig
            //
            //    GlobalResponseHeaders = 
            //         "Access-Control-Allow-Origin", "*" ,
            //         "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS" ,
            //         "Access-Control-Allow-Headers", "Content-Type" ,
            //    ,
            //);


            //AutoQuery
            Plugins.Add(new AutoQueryFeature  MaxLimit = 100000 );
            //Cache
            container.Register<ICacheClient>(new MemoryCacheClient());

            container.Register<IAuthRepository>(c =>
                new MyOrmLiteAuthRepository(c.Resolve<IDbConnectionFactory>())
                
                    UseDistinctRoleTables = AppSettings.Get("UseDistinctRoleTables", true),
                );
            OrmLiteConfig.BeforeExecFilter = dbCmd => Debug.WriteLine(dbCmd.GetDebugString());

            bool ShouldWipeAndReloadDb = false;
            var environmentVariable = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");

            if (environmentVariable == "LocalMemory" || environmentVariable == "LocalSQLServer")
            
                ShouldWipeAndReloadDb = true;
                //Init auth tables
                container.Resolve<IAuthRepository>().InitSchema();
            
            var authRepo = (MyOrmLiteAuthRepository)container.Resolve<IAuthRepository>();

            //Wipe and reload if using in memory SQL
            if (ShouldWipeAndReloadDb)
            
                DatabaseInitService dis = new DatabaseInitService();
                dis.ResetDatabase();
                SessionService.ResetUsers(authRepo);
                dis.InitializeTablesAndData();
            
        
    


public class CustomUserSession : AuthUserSession

    [DataMember]
    public string CustomName  get; set; 

    [DataMember]
    public string CustomInfo  get; set; 


【问题讨论】:

【参考方案1】:

错误消息“令牌已失效”only occurs when the issue date of the JWT 令牌是在您配置的InvalidateTokensIssuedBefore 之前发出的:

InvalidateTokensIssuedBefore = DateTime.Now,

您不太可能希望在应用程序域重新启动时使令牌无效,这类似于永远不会拥有持久的身份验证密钥(即仅使用瞬态 AesUtils.CreateKey()),因为在应用程序域重新启动/循环之间创建的任何 JWT 都会自动失效.

【讨论】:

将其设置为 InvalidateTokensIssuedBefore = DateTime.Now.AddHours(24) 导致它根本无法登录。注释掉该行解决了这个问题。 此外,我们在 Azure 应用服务中运行它。当我们重载应用服务时,它会导致所有不记名令牌随着 datetime.now 设置过期 @SteveColeman 预计会导致在接下来的 24 小时内创建的每个 JWT 都无效。注意:Issued At claim (iat) is stored in Unix Time 因此您还应该使用 UTC 进行日期比较,例如DateTime.UtcNow.AddDays(-1) 但这不是 JWT 的使用方式,您的系统应该被设计为在您设置为 TimeSpan.FromHours(24) 的到期日期(即 JWT 的隐式合同)之前有效。 InvalidateTokensIssuedBefore 是一个逃生舱,当需要立即使所有 JWT 失效时,这应该是一个恒定的日期。

以上是关于Servicestack导致承载令牌无效的主要内容,如果未能解决你的问题,请参考以下文章

XSLT 无效令牌导致 XML 文档无效

APNS:无效令牌导致所有后续推送通知失败

使用 Firebase 登录 Facebook 导致无效 OAuth 访问令牌错误

直接访问登录表单时未设置会话 cookie,导致 CSRF 令牌无效

通过 ServiceStack api 使用 Linq2Twitter 和缓存的 OAuth 令牌

Json.NET 中的异常:处于“开​​始”状态的令牌 PropertyName 将导致无效的 JavaScript 对象