Exemple #1
0
        private CookieAuthenticationOptions SetupAppCookie(
            // CookieAuthenticationOptions options,
            CookieAuthenticationEvents cookieEvents,
            cloudscribe.Core.Identity.SiteAuthCookieValidator siteValidator,
            string scheme,
            cloudscribe.Core.Models.SiteSettings tenant
            )
        {
            var options = new CookieAuthenticationOptions();

            options.AuthenticationScheme = $"{scheme}-{tenant.SiteFolderName}";
            options.CookieName           = $"{scheme}-{tenant.SiteFolderName}";
            options.CookiePath           = "/" + tenant.SiteFolderName;

            var tenantPathBase = string.IsNullOrEmpty(tenant.SiteFolderName)
                ? PathString.Empty
                : new PathString("/" + tenant.SiteFolderName);

            options.LoginPath  = tenantPathBase + "/account/login";
            options.LogoutPath = tenantPathBase + "/account/logoff";

            cookieEvents.OnValidatePrincipal = siteValidator.ValidatePrincipal;
            options.Events = cookieEvents;

            options.AutomaticAuthenticate = true;
            options.AutomaticChallenge    = true;

            return(options);
        }
Exemple #2
0
 /// <summary>
 /// Create an instance of the options initialized with the default values
 /// </summary>
 public CookieAuthenticationOptions()
 {
     ExpireTimeSpan     = TimeSpan.FromDays(14);
     ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
     SlidingExpiration  = true;
     Events             = new CookieAuthenticationEvents();
 }
Exemple #3
0
    public static CookieAuthenticationEvents GetModifiedEvents(CookieAuthenticationEvents standardEvents)
    {
        var options = new CookieAuthenticationEvents()
        {
            OnRedirectToLogin = (ctx) =>
            {
                if (ctx.Request.Path.StartsWithSegments("/api") && ctx.Response.StatusCode == 200)
                {
                    ctx.Response.StatusCode = 401;
                    return(Task.CompletedTask);
                }

                return(standardEvents.OnRedirectToLogin(ctx));
            },
            OnRedirectToAccessDenied = (ctx) =>
            {
                if (ctx.Request.Path.StartsWithSegments("/api") && ctx.Response.StatusCode == 200)
                {
                    ctx.Response.StatusCode = 403;
                    return(Task.CompletedTask);
                }

                return(standardEvents.OnRedirectToAccessDenied(ctx));
            },
            OnCheckSlidingExpiration = (ctx) => standardEvents.OnCheckSlidingExpiration(ctx),
            OnRedirectToLogout       = (ctx) => standardEvents.OnRedirectToLogout(ctx),
            OnRedirectToReturnUrl    = (ctx) => standardEvents.OnRedirectToLogout(ctx),
            OnSignedIn          = (ctx) => standardEvents.OnSignedIn(ctx),
            OnSigningIn         = (ctx) => standardEvents.OnSigningIn(ctx),
            OnSigningOut        = (ctx) => standardEvents.OnSigningOut(ctx),
            OnValidatePrincipal = (ctx) => standardEvents.OnValidatePrincipal(ctx)
        };

        return(options);
    }
Exemple #4
0
        /// <summary>
        /// Register cookie authentication related actors
        /// </summary>
        /// <remarks>
        /// Remember to configure 'UseCookieAuthentication()' and 'UseAuthorization()'
        /// after 'UseRouting()', but before 'UseEndpoints()'
        /// </remarks>
        /// <param name="services"></param>
        /// <param name="configRoot"></param>
        /// <param name="mode"></param>
        public static AuthenticationBuilder AddCookieAuthentication(
            this IServiceCollection services,
            IConfigurationRoot configRoot,
            SameSiteMode mode = SameSiteMode.Lax
            )
        {
            var config = configRoot
                         .GetSection(WebConfiguration.AUTHENTICATION)
                         .GetSection(WebConfiguration.AUTHENTICATION_COOKIE)
                         .Get <CookieAuthenticationConfiguration>();

            if (config == null)
            {
                var configPath = $"{WebConfiguration.AUTHENTICATION}:{WebConfiguration.AUTHENTICATION_COOKIE}";
                throw new Exception($"Unable to find configuration for '{configPath}' <CookieAuthenticationConfiguration>");
            }

            var cookie = new CookieBuilder
            {
                Name     = config.CookieName,
                SameSite = mode
            };

            var cookieEvents = new CookieAuthenticationEvents
            {
                OnRedirectToAccessDenied = context =>
                {
                    context.Response.StatusCode = 403; // Don't redirect, set to forbidden
                    return(Task.CompletedTask);
                },
                OnRedirectToLogin = context =>
                {
                    context.Response.StatusCode = 401; // Don't redirect, set to unauthorized
                    return(Task.CompletedTask);
                }
            };

            services.AddSingleton((sp) => config);

            // Register actors
            return(services
                   .AddAuthentication((options) =>
            {
                options.DefaultAuthenticateScheme =
                    options.DefaultChallengeScheme =
                        options.DefaultScheme =
                            options.DefaultSignInScheme = config.AuthenticationScheme;
            })
                   .AddCookie(config.AuthenticationScheme, options =>
            {
                options.AccessDeniedPath = new PathString(config.AccessDeniedPath);
                options.Cookie = cookie;
                options.Events = cookieEvents;
                options.LoginPath = new PathString(config.LoginPath);
            }));
        }
Exemple #5
0
 public SiteIdentityOptionsResolver(
     IHttpContextAccessor httpContextAccessor,
     // CookieAuthenticationEvents cookieEvents,
     SiteAuthCookieValidator siteValidator
     )
 {
     this.httpContextAccessor = httpContextAccessor;
     this.cookieEvents        = new CookieAuthenticationEvents();
     this.siteValidator       = siteValidator;
 }
Exemple #6
0
 public SiteIdentityOptionsResolver(
     IHttpContextAccessor httpContextAccessor,
     IOptions <MultiTenantOptions> multiTenantOptionsAccessor,
     SiteAuthCookieValidator siteValidator
     )
 {
     this.httpContextAccessor = httpContextAccessor;
     this.cookieEvents        = new CookieAuthenticationEvents();
     this.siteValidator       = siteValidator;
     multiTenantOptions       = multiTenantOptionsAccessor.Value;
 }
 public SessionCookieOptions(
     CookieAuthenticationEvents cookieAuthenticationEvents,
     string authenticationType,
     string loginPath,
     string logoutPath)
 {
     CookieAuthenticationEvents = cookieAuthenticationEvents;
     AuthenticationType         = authenticationType;
     LoginPath  = loginPath;
     LogoutPath = logoutPath;
 }
 /// <summary>
 /// Create an instance of the options initialized with the default values
 /// </summary>
 public CookieAuthenticationOptions()
 {
     AuthenticationScheme  = CookieAuthenticationDefaults.AuthenticationScheme;
     AutomaticAuthenticate = true;
     ReturnUrlParameter    = CookieAuthenticationDefaults.ReturnUrlParameter;
     ExpireTimeSpan        = TimeSpan.FromDays(14);
     SlidingExpiration     = true;
     CookieHttpOnly        = true;
     CookieSecure          = CookieSecurePolicy.SameAsRequest;
     SystemClock           = new SystemClock();
     Events = new CookieAuthenticationEvents();
 }
Exemple #9
0
        private CookieAuthenticationOptions SetupAppCookie(
            CookieAuthenticationEvents cookieEvents,
            cloudscribe.Core.Identity.SiteAuthCookieValidator siteValidator,
            string scheme,
            bool useRelatedSitesMode,
            cloudscribe.Core.Models.SiteSettings tenant
            )
        {
            var options = new CookieAuthenticationOptions();

            if (useRelatedSitesMode)
            {
                options.AuthenticationScheme = scheme;
                options.CookieName           = scheme;
                options.CookiePath           = "/";
            }
            else
            {
                options.AuthenticationScheme     = $"{scheme}-{tenant.SiteFolderName}";
                options.CookieName               = $"{scheme}-{tenant.SiteFolderName}";
                options.CookiePath               = "/" + tenant.SiteFolderName;
                cookieEvents.OnValidatePrincipal = siteValidator.ValidatePrincipal;
            }

            var tenantPathBase = string.IsNullOrEmpty(tenant.SiteFolderName)
                ? PathString.Empty
                : new PathString("/" + tenant.SiteFolderName);

            options.LoginPath        = tenantPathBase + "/account/login";
            options.LogoutPath       = tenantPathBase + "/account/logoff";
            options.AccessDeniedPath = tenantPathBase + "/account/accessdenied";

            options.Events = cookieEvents;

            options.AutomaticAuthenticate = true;
            options.AutomaticChallenge    = false;

            options.CookieSecure = environment.IsDevelopment()
            ? CookieSecurePolicy.SameAsRequest
            : CookieSecurePolicy.Always;



            return(options);
        }
        public static CookieAuthenticationOptions SetupAppCookie(
            this IApplicationBuilder app,
            SiteAuthCookieValidator siteValidator,
            string scheme,
            bool useRelatedSitesMode,
            SiteContext tenant,
            CookieSecurePolicy cookieSecure = CookieSecurePolicy.SameAsRequest
            )
        {
            var cookieEvents = new CookieAuthenticationEvents();
            var options      = new CookieAuthenticationOptions();

            if (useRelatedSitesMode)
            {
                options.AuthenticationScheme = scheme;
                options.CookieName           = scheme;
                options.CookiePath           = "/";
            }
            else
            {
                //options.AuthenticationScheme = $"{scheme}-{tenant.SiteFolderName}";
                options.AuthenticationScheme     = scheme;
                options.CookieName               = $"{scheme}-{tenant.SiteFolderName}";
                options.CookiePath               = "/" + tenant.SiteFolderName;
                cookieEvents.OnValidatePrincipal = siteValidator.ValidatePrincipal;
            }

            var tenantPathBase = string.IsNullOrEmpty(tenant.SiteFolderName)
                ? PathString.Empty
                : new PathString("/" + tenant.SiteFolderName);

            options.LoginPath        = tenantPathBase + "/account/login";
            options.LogoutPath       = tenantPathBase + "/account/logoff";
            options.AccessDeniedPath = tenantPathBase + "/account/accessdenied";

            options.Events = cookieEvents;

            options.AutomaticAuthenticate = true;
            options.AutomaticChallenge    = false;

            options.CookieSecure = cookieSecure;

            return(options);
        }
        public static void DisableRedirectForPath(

            this CookieAuthenticationEvents events, Expression <Func <CookieAuthenticationEvents, Func <RedirectContext <CookieAuthenticationOptions>, Task> > > expr, string path, int statuscode)
        {
            string propertyName = ((MemberExpression)expr.Body).Member.Name; var oldHandler = expr.Compile().Invoke(events);
            Func <RedirectContext <CookieAuthenticationOptions>, Task> newHandler = context => {
                if (context.Request.Path.StartsWithSegments(path))
                {
                    context.Response.StatusCode = statuscode;
                }
                else
                {
                    oldHandler(context);
                }
                return(Task.CompletedTask);
            };

            typeof(CookieAuthenticationEvents).GetProperty(propertyName).SetValue(events, newHandler);
        }
Exemple #12
0
        /// <summary>
        /// Register cookie authentication related actors
        /// </summary>
        /// <param name="services"></param>
        /// <param name="config"></param>
        public static IServiceCollection AddCookieAuthentication(this IServiceCollection services, IConfigurationRoot config)
        {
            var cookieConfig = config
                               .GetSection(WebConfiguration.AUTHENTICATION)
                               .GetSection(WebConfiguration.AUTHENTICATION_COOKIE)
                               .Get <CookieAuthenticationConfiguration>();

            // Configuration
            var cookie = new CookieBuilder
            {
                Name     = cookieConfig.CookieName,
                SameSite = SameSiteMode.Lax
            };

            var cookieEvents = new CookieAuthenticationEvents
            {
                OnRedirectToAccessDenied = context =>
                {
                    context.Response.StatusCode = 403; // Don't redirect, set to forbidden
                    return(Task.CompletedTask);
                },
                OnRedirectToLogin = context =>
                {
                    context.Response.StatusCode = 401; // Don't redirect, set to unauthorized
                    return(Task.CompletedTask);
                }
            };

            // Register actors
            services
            .AddSingleton((sp) => cookieConfig)
            .AddAuthentication(cookieConfig.AuthenticationScheme)
            .AddCookie(cookieConfig.AuthenticationScheme, options =>
            {
                options.AccessDeniedPath = new PathString(cookieConfig.AccessDeniedPath);
                options.Cookie           = cookie;
                options.Events           = cookieEvents;
                options.LoginPath        = new PathString(cookieConfig.LoginPath);
            });

            return(services);
        }
Exemple #13
0
        private CookieAuthenticationEvents get_sams_authentication_events()
        {
            //https://stackoverflow.com/questions/52175302/handling-expired-refresh-tokens-in-asp-net-core

            var sams_endpoint_authorization    = Configuration["sams:endpoint_authorization"];
            var sams_endpoint_token            = Configuration["sams:endpoint_token"];
            var sams_endpoint_user_info        = Configuration["sams:endpoint_user_info"];
            var sams_endpoint_token_validation = Configuration["sams:token_validation"];
            var sams_endpoint_user_info_sys    = Configuration["sams:user_info_sys"];
            var sams_client_id     = Configuration["sams:client_id"];
            var sams_client_secret = Configuration["sams:client_secret"];
            var sams_callback_url  = Configuration["sams:callback_url"];

            var result = new CookieAuthenticationEvents
            {
                OnValidatePrincipal = context =>
                {
                    //check to see if user is authenticated first
                    if (context.Principal.Identity.IsAuthenticated)
                    {
                        var expires_at = context.Request.Cookies["expires_at"];

                        var expires_at_time = DateTimeOffset.Parse(expires_at);

/*
 *                      var accessToken = context.Request.HttpContext.Session.GetString("access_token");
 *                      var refreshToken = context.Request.HttpContext.Session.GetString("refresh_token");
 *                      var exp = context.Request.HttpContext.Session.GetInt32("expires_in");
 */

                        /*
                         *          var tokens = context.Properties.GetTokens();
                         *          var refreshToken = tokens.FirstOrDefault(t => t.Name == "refresh_token");
                         *          var accessToken = tokens.FirstOrDefault(t => t.Name == "access_token");
                         *          var exp = tokens.FirstOrDefault(t => t.Name == "expires_at");
                         *          var expires = DateTime.Parse(exp.Value);
                         */

                        //context.Request.Cookies.["sid"].
                        // var expires = DateTime.Parse(exp.ToString());
                        //check to see if the token has expired
                        if (expires_at_time.DateTime < DateTime.Now)
                        {
                            try
                            {
                                var sid = context.Request.Cookies["sid"];

                                string request_string = Program.config_couchdb_url + $"/session/{sid}";
                                var    curl           = new cURL("GET", null, request_string, null, Program.config_timer_user_name, Program.config_timer_password);
                                string session_json   = curl.execute();
                                var    session        = Newtonsoft.Json.JsonConvert.DeserializeObject <mmria.common.model.couchdb.session> (session_json);

                                var userName = context.Principal.Identities.First(
                                    u => u.IsAuthenticated &&
                                    u.HasClaim(c => c.Type == ClaimTypes.Name)).FindFirst(ClaimTypes.Name).Value;


                                if (!userName.Equals(session.user_id, StringComparison.OrdinalIgnoreCase))
                                {
                                    context.RejectPrincipal();
                                    return(Task.CompletedTask);
                                }

                                var accessToken  = session.data["access_token"];
                                var refreshToken = session.data["refresh_token"];
                                var exp          = session.data["expires_at"];
                                expires_at_time = DateTimeOffset.Parse(exp);

                                // server-side check for expiration
                                if (expires_at_time.DateTime < DateTime.Now)
                                {
                                    //token is expired, let's attempt to renew
                                    var tokenEndpoint = sams_endpoint_token;
                                    var tokenClient   = new mmria.server.util.TokenClient(Configuration);

                                    //var name = HttpContext.Session.GetString(SessionKeyName);
                                    //var name = HttpContext.Session.GetString(SessionKeyName);

                                    var tokenResponse = tokenClient.get_refresh_token(accessToken.ToString(), refreshToken.ToString()).Result;
                                    //check for error while renewing - any error will trigger a new login.
                                    if (tokenResponse.is_error)
                                    {
                                        //reject Principal
                                        context.RejectPrincipal();
                                        return(Task.CompletedTask);
                                    }
                                    //set new token values
                                    refreshToken = tokenResponse.refresh_token;
                                    accessToken  = tokenResponse.access_token;
                                    var unix_time = DateTimeOffset.UtcNow.AddSeconds(tokenResponse.expires_in);

                                    session.data["access_token"]  = accessToken;
                                    session.data["refresh_token"] = refreshToken;
                                    session.data["expires_at"]    = unix_time.ToString();

                                    context.Response.Cookies.Append("expires_at", unix_time.ToString());


                                    session.date_last_updated = DateTime.UtcNow;


                                    var Session_Message = new mmria.server.model.actor.Session_Message
                                                          (
                                        session._id,               //_id =
                                        session._rev,              //_rev =
                                        session.date_created,      //date_created =
                                        session.date_last_updated, //date_last_updated =
                                        session.date_expired,      //date_expired =

                                        session.is_active,         //is_active =
                                        session.user_id,           //user_id =
                                        session.ip,                //ip =
                                        session.session_event_id,  // session_event_id =
                                        session.data
                                                          );

                                    Program.actorSystem.ActorOf(Props.Create <mmria.server.model.actor.Post_Session>()).Tell(Session_Message);

                                    //trigger context to renew cookie with new token values
                                    context.ShouldRenew = true;
                                    return(Task.CompletedTask);
                                }
                            }
                            catch (Exception ex)
                            {
                                // do nothing for now document doesn't exsist.
                                System.Console.WriteLine($"err caseController.Post\n{ex}");
                            }
                        }
                    }
                    return(Task.CompletedTask);
                }
            };

            return(result);
        }
Exemple #14
0
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(
            IApplicationBuilder app,
            IHostingEnvironment env,
            ILoggerFactory loggerFactory,
            IOptions <cloudscribe.Core.Models.MultiTenantOptions> multiTenantOptionsAccessor,
            IServiceProvider serviceProvider
            )
        {
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            loggerFactory.AddDebug();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
                app.UseBrowserLink();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseStaticFiles();

            app.UseSession();

            app.UseMultitenancy <cloudscribe.Core.Models.SiteSettings>();

            //app.UseTenantContainers<SiteSettings>();
            var multiTenantOptions = multiTenantOptionsAccessor.Value;

            app.UsePerTenant <cloudscribe.Core.Models.SiteSettings>((ctx, builder) =>
            {
                var tenant = ctx.Tenant;

                var shouldUseFolder = !multiTenantOptions.UseRelatedSitesMode &&
                                      multiTenantOptions.Mode == cloudscribe.Core.Models.MultiTenantMode.FolderName &&
                                      tenant.SiteFolderName.Length > 0;

                var externalCookieOptions = SetupOtherCookies(cloudscribe.Core.Identity.AuthenticationScheme.External, tenant);
                builder.UseCookieAuthentication(externalCookieOptions);

                var twoFactorRememberMeCookieOptions = SetupOtherCookies(cloudscribe.Core.Identity.AuthenticationScheme.TwoFactorRememberMe, tenant);
                builder.UseCookieAuthentication(twoFactorRememberMeCookieOptions);

                var twoFactorUserIdCookie = SetupOtherCookies(cloudscribe.Core.Identity.AuthenticationScheme.TwoFactorUserId, tenant);
                builder.UseCookieAuthentication(twoFactorUserIdCookie);

                var cookieEvents     = new CookieAuthenticationEvents();
                var logger           = loggerFactory.CreateLogger <cloudscribe.Core.Identity.SiteAuthCookieValidator>();
                var cookieValidator  = new cloudscribe.Core.Identity.SiteAuthCookieValidator(logger);
                var appCookieOptions = SetupAppCookie(
                    cookieEvents,
                    cookieValidator,
                    cloudscribe.Core.Identity.AuthenticationScheme.Application,
                    tenant
                    );
                builder.UseCookieAuthentication(appCookieOptions);

                // known issue here is if a site is updated to populate the
                // social auth keys, it currently requires a restart so that the middleware gets registered
                // in order for it to work or for the social auth buttons to appear
                builder.UseSocialAuth(ctx.Tenant, externalCookieOptions, shouldUseFolder);
            });


            UseMvc(app, multiTenantOptions.Mode == cloudscribe.Core.Models.MultiTenantMode.FolderName);

            var storage = Configuration["DevOptions:DbPlatform"];

            switch (storage)
            {
            case "NoDb":
                CoreNoDbStartup.InitializeDataAsync(app.ApplicationServices).Wait();
                break;

            case "ef":
            default:
                // this creates ensures the database is created and initial data
                CoreEFStartup.InitializeDatabaseAsync(app.ApplicationServices).Wait();

                // this one is only needed if using cloudscribe Logging with EF as the logging storage
                //cloudscribe.Logging.EF.LoggingDbInitializer.InitializeDatabaseAsync(app.ApplicationServices).Wait();

                break;
            }
        }
Exemple #15
0
        /// <summary>
        /// 权限控制核心,即必须的配置
        /// </summary>
        /// <param name="services"></param>
        /// <param name="action"></param>
        public static void AddCorePermission(this IServiceCollection services, Action <PermissionOptions> action)
        {
            services.AddSingleton <IToken, Token>();
            #region 身份验证
            var permissionOption = new PermissionOptions();
            action(permissionOption);
            //addAuthentication不放到AddPermissionCore方法里,是为了外部可自己配置
            // 当未通过authenticate时(如无token或是token出错时),会返回401,当通过了authenticate但没通过authorize时,会返回403。
            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
            .AddCookie(
                CookieAuthenticationDefaults.AuthenticationScheme, options =>
            {
                //下面的委托方法只会在第一次cookie验证时调用,调用时会用到上面的permissionOption变量,但其实permissionOption变量是在以前已经初始化的,所以在此方法调用之前,permissionOption变量不会被释放
                options.Cookie.Name            = "auth";
                options.AccessDeniedPath       = permissionOption.AccessDeniedPath; // 当403时,返回到无授权界面
                options.LoginPath              = permissionOption.LoginPath;        // 当401时,返回到登录界面,会自动在url后加上returnUrl=xxx
                options.ExpireTimeSpan         = permissionOption.ExpireTimeSpan != default ? permissionOption.ExpireTimeSpan : new TimeSpan(12, 0, 0);
                options.ForwardDefaultSelector = context =>
                {
                    string authorization = context.Request.Headers["Authorization"];
                    //身份验证的顺序为jwt、cookie
                    if (authorization != null && authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
                    {
                        return(JwtBearerDefaults.AuthenticationScheme);
                    }
                    else
                    {
                        return(CookieAuthenticationDefaults.AuthenticationScheme);
                    }
                };
                var cookieAuthenticationEvents = new CookieAuthenticationEvents
                {
                    OnSignedIn = context =>
                    {
                        return(Task.CompletedTask);
                    },
                    OnSigningOut = context =>
                    {
                        return(Task.CompletedTask);
                    }
                };
                options.Events = cookieAuthenticationEvents;
            })
            .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
            {
                // jwt可用对称和非对称算法进行验签
                SecurityKey key;
                if (permissionOption.IsAsymmetric)
                {
                    key = new RsaSecurityKey(RSAHelper.GetRSAParametersFromFromPublicPem(permissionOption.RsaPublicKey));
                }
                else
                {
                    key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(permissionOption.SymmetricSecurityKey));
                }
                options.TokenValidationParameters = new TokenValidationParameters()
                {
                    NameClaimType    = PermissionConstant.userIdClaim,
                    RoleClaimType    = PermissionConstant.roleIdsClaim,
                    ValidIssuer      = permissionOption.Issuer,
                    ValidAudience    = permissionOption.Audience,
                    IssuerSigningKey = key,
                    ValidateIssuer   = false,
                    ValidateAudience = false
                };
                var jwtBearerEvents = new JwtBearerEvents
                {
                    OnMessageReceived = context =>
                    {
                        return(Task.CompletedTask);
                    },
                    OnTokenValidated = context =>
                    {
                        return(Task.CompletedTask);
                    },
                    OnAuthenticationFailed = context =>
                    {
                        return(Task.CompletedTask);
                    }
                };
                options.Events = jwtBearerEvents;
            });
            #endregion
            #region 授权

            //权限控制只要在配置IServiceCollection,不需要额外配置app管道
            //权限控制参考:https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies?view=aspnetcore-2.2
            //handler和requirement有几种关系:1 handler对多requirement(此时handler实现IAuthorizationHandler);1对1(实现AuthorizationHandler<PermissionRequirement>),和多对1
            //所有的handler都要注入到services,用services.AddSingleton<IAuthorizationHandler, xxxHandler>(),而哪个requirement用哪个handler,低层会自动匹配。最后将requirement对到policy里即可
            services.AddAuthorization(options =>
            {
                // 增加鉴权策略,并告知这个策略要判断用户是否获得了PermissionRequirement这个Requirement
                options.AddPolicy(PermissionConstant.PermissionAuthorizePolicy, policyBuilder =>
                {
                    policyBuilder.AddRequirements(new PermissionRequirement());
                });
                //options.AddPolicy(PermissionConstant.OnlyAuthenticationPolicy, policyBuilder =>
                // {
                //     policyBuilder.AddRequirements(new OnlyAuthenticationRequirement());
                // });
            });
            services.AddScoped <IAuthorizationHandler, PermissionRequirementHandler>();
            services.AddMemoryCache();
            services.TryAddScoped <IApplicationContext, ApplicationContext>();
            services.AddHttpContextAccessor();
            services.Configure(action);
            #endregion
        }