/// <summary>
        /// In order to ensure that the Web API only accepts tokens from tenants where it has been consented and provisioned, a token that
        /// has neither Roles nor Scopes claims should be rejected. To enforce that rule, add an event handler to the beginning of the
        /// <see cref="JwtBearerEvents.OnTokenValidated"/> handler chain that rejects tokens that don't meet the rules.
        /// </summary>
        /// <param name="events">The <see cref="JwtBearerEvents"/> object to modify.</param>
        /// <param name="jwtBearerScheme">The JWT bearer scheme name to be used. By default it uses "Bearer".</param>
        internal static void ChainOnTokenValidatedEventForClaimsValidation(JwtBearerEvents events, string jwtBearerScheme)
        {
            var tokenValidatedHandler = events.OnTokenValidated;

            events.OnTokenValidated = async context =>
            {
                if (!context !.Principal !.Claims.Any(x => x.Type == ClaimConstants.Scope ||
                                                      x.Type == ClaimConstants.Scp ||
                                                      x.Type == ClaimConstants.Roles ||
                                                      x.Type == ClaimConstants.Role))
                {
                    context.Fail(string.Format(CultureInfo.InvariantCulture, IDWebErrorMessage.NeitherScopeOrRolesClaimFoundInToken, jwtBearerScheme));
                }

                await tokenValidatedHandler(context).ConfigureAwait(false);
            };
        }
        /// <summary>
        ///   Wraps an instance of <see cref="JwtBearerEvents" /> with a behavior
        ///   checks for a token in the query string with a name specified in the
        ///   <paramref name="queryStringParameterName" /> parameter.
        /// </summary>
        /// <param name="inner">
        ///   A base <see cref="JwtBearerEvents" /> implementation that will gain
        ///   this additional query string inspection behavior.
        /// </param>
        /// <param name="queryStringParameterName">
        ///   The name of the query string parameter that will be sought from requests
        ///   in order to extract a token.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///   Thrown when <paramref name="inner" /> or
        ///   <paramref name="queryStringParameterName" /> is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        ///   Thrown when <paramref name="queryStringParameterName" /> is an invalid name
        ///   for a query string parameter.
        /// </exception>
        public QueryStringJwtBearerEventsWrapper(JwtBearerEvents inner, string queryStringParameterName) :
            base(inner)
        {
            if (queryStringParameterName == null)
            {
                throw new ArgumentNullException(nameof(queryStringParameterName));
            }
            else if (String.IsNullOrWhiteSpace(queryStringParameterName))
            {
                throw new ArgumentException(
                          $"The '{nameof(queryStringParameterName)}' cannot be null or whitespace.",
                          nameof(queryStringParameterName)
                          );
            }

            this.QueryStringParameterName = queryStringParameterName;
        }
Пример #3
0
        private void AddAutheticationAndAuthorization(IServiceCollection services)
        {
            var tokenValidationParameters = new TokenValidationParameters()
            {
                ValidIssuer              = Configuration["Tokens:Issuer"],
                ValidAudience            = Configuration["Tokens:Audience"],
                ValidateIssuerSigningKey = true,
                IssuerSigningKey         = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Tokens:Key"])),
                ValidateLifetime         = true
            };
            var logger      = LoggerFactory.CreateLogger("Jwt events logger");
            var tokenEvents = new JwtBearerEvents
            {
                OnAuthenticationFailed = context =>
                {
                    logger.LogInformation("OnAuthenticationFailed: " +
                                          context.Exception.Message);
                    return(Task.CompletedTask);
                },
                OnTokenValidated = context =>
                {
                    logger.LogInformation("OnTokenValidated: " +
                                          context.SecurityToken);
                    return(Task.CompletedTask);
                }
            };

            services.AddIdentity <SystemUser, IdentityRole>()
            .AddEntityFrameworkStores <ToggleContext>();
            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme    = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(o =>
            {
                o.Audience = Configuration["Tokens:Audience"];
                o.TokenValidationParameters = tokenValidationParameters;
                o.Events = tokenEvents;
            });

            services.AddAuthorization(cfg =>
            {
                cfg.AddPolicy("Administrators", p => p.RequireClaim("SuperUser", "True"));
            });
        }
        /// <summary>
        /// Subscribes to all the JwtBearer events, to help debugging, while
        /// preserving the previous handlers (which are called).
        /// </summary>
        /// <param name="events">Events to subscribe to.</param>
        /// <returns><see cref="JwtBearerEvents"/> for chaining.</returns>
        public JwtBearerEvents Subscribe(JwtBearerEvents events)
        {
            events ??= new JwtBearerEvents();

            s_onAuthenticationFailed      = events.OnAuthenticationFailed;
            events.OnAuthenticationFailed = OnAuthenticationFailedAsync;

            s_onMessageReceived      = events.OnMessageReceived;
            events.OnMessageReceived = OnMessageReceivedAsync;

            s_onTokenValidated      = events.OnTokenValidated;
            events.OnTokenValidated = OnTokenValidatedAsync;

            s_onChallenge      = events.OnChallenge;
            events.OnChallenge = OnChallengeAsync;

            return(events);
        }
Пример #5
0
        private void ConfigureAuthService(IServiceCollection services)
        {
            // prevent from mapping "sub" claim to nameidentifier.
            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub");

            var identityAuthority = Configuration.GetValue <string>("IdentityAuthority");
            var audience          = Configuration.GetValue <string>("IdentityAudience");

            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme    = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(options =>
            {
                var events         = new JwtBearerEvents();
                events.OnChallenge = (context) =>
                { return(Task.FromResult(0)); };
                events.OnAuthenticationFailed = (context) =>
                { return(Task.FromResult(0)); };
                events.OnForbidden = (context) =>
                { return(Task.FromResult(0)); };
                events.OnTokenValidated = (context) =>
                { return(Task.FromResult(0)); };
                events.OnMessageReceived = (context) =>
                { return(Task.FromResult(0)); };
                options.Events = events;

                options.Authority = identityAuthority;
                options.TokenValidationParameters.ValidAudience = audience;
            });

            //services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            //   .AddMicrosoftIdentityWebApi(options =>
            //   {
            //       Configuration.Bind("AzureAdB2C", options);

            //       options.TokenValidationParameters.NameClaimType = "name";
            //   },
            //   options => {
            //       Configuration.Bind("AzureAdB2C", options);
            //   });
        }
        public static IServiceCollection AddTokenAuthentication(
            this IServiceCollection services,
            IConfiguration configuration,
            JwtBearerEvents events = null)
        {
            var secret = configuration
                         .GetSection(nameof(ApplicationSettings))
                         .GetValue <string>(nameof(ApplicationSettings.Secret));

            var key = Encoding.ASCII.GetBytes(secret);

            IdentityModelEventSource.ShowPII = true;

            services
            .AddAuthentication(authentication =>
            {
                authentication.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                authentication.DefaultChallengeScheme    = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(bearer =>
            {
                bearer.RequireHttpsMetadata      = false;
                bearer.SaveToken                 = true;
                bearer.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey         = new SymmetricSecurityKey(key),
                    ValidateIssuer           = false,
                    ValidateAudience         = false
                };

                if (events != null)
                {
                    bearer.Events = events;
                }
            });

            services.AddHttpContextAccessor();
            services.AddScoped <ICurrentUserService, CurrentUserService>();

            return(services);
        }
        /// <summary>
        /// Subscribes to all the JwtBearer events, to help debugging, while
        /// preserving the previous handlers (which are called)
        /// </summary>
        /// <param name="events">Events to subscribe to</param>
        public static JwtBearerEvents Subscribe(JwtBearerEvents events)
        {
            if (events == null)
            {
                events = new JwtBearerEvents();
            }

            onAuthenticationFailed        = events.OnAuthenticationFailed;
            events.OnAuthenticationFailed = OnAuthenticationFailed;

            onMessageReceived        = events.OnMessageReceived;
            events.OnMessageReceived = OnMessageReceived;

            onTokenValidated        = events.OnTokenValidated;
            events.OnTokenValidated = OnTokenValidated;

            onChallenge        = events.OnChallenge;
            events.OnChallenge = OnChallenge;

            return(events);
        }
        private static JwtBearerEvents buildStackedEventHandler <T>(JwtBearerEvents events, Action <Func <T, Task> > setEvent, params Func <T, Task>[] eventContextHandler)
            where T : ResultContext <JwtBearerOptions>
        {
            setEvent(async(context) => {
                foreach (var handler in eventContextHandler)
                {
                    if (handler != null)
                    {
                        await handler.Invoke(context);
                    }

                    // We want to break if result has been set.
                    if (context.Result != null)
                    {
                        break;
                    }
                }
            });

            return(events);
        }
        public void Constructor_WithCustomQueryStringParameterName_InvalidParameterName(
            string queryStringParameterName)
        {
            // Arrange

            var inner = new JwtBearerEvents();

            // Act

            var exception = Record.Exception(
                () => new QueryStringJwtBearerEventsWrapper(inner, queryStringParameterName)
                );

            // Assert

            Assert.IsType <ArgumentException>(exception);

            Assert.Equal(
                $"The 'queryStringParameterName' cannot be null or whitespace." +
                Environment.NewLine + "Parameter name: queryStringParameterName",
                exception.Message
                );
        }
 protected override JwtBearerEvents CreateJwtBearerEvents(JwtBearerEvents inner)
 {
     return(this.CreateQueryStringJwtBearerEvents(inner));
 }
 public static JwtBearerEvents WhenTokenValidated(this JwtBearerEvents events, params Func <TokenValidatedContext, Task>[] tokenValidatedContextHandler) =>
 buildStackedEventHandler(events,
                          eventContextHandler => events.OnTokenValidated = eventContextHandler,
                          tokenValidatedContextHandler);
 public static JwtBearerEvents WhenMessageReceived(this JwtBearerEvents events, params Func <MessageReceivedContext, Task>[] messageReceivedContextHandler) =>
 buildStackedEventHandler(events,
                          eventContextHandler => events.OnMessageReceived = eventContextHandler,
                          messageReceivedContextHandler);
Пример #13
0
        private static void CreateJwtBearerOptions(JwtBearerOptions o, string issuer, SymmetricSecurityKey signingKey, IHostingEnvironment environment, JwtBearerEvents events)
        {
            if (environment.IsDevelopment())
            {
                o.RequireHttpsMetadata = false;
            }

            o.Audience  = issuer;
            o.Authority = null;

            if (events != null)
            {
                o.Events = events;
            }

            o.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidIssuer    = issuer,

                ValidateAudience = true,
                ValidAudience    = issuer,

                ValidateIssuerSigningKey = true,
                IssuerSigningKey         = signingKey,

                RequireExpirationTime = true,
                ValidateLifetime      = true,

                ClockSkew = TimeSpan.Zero,

                NameClaimType = ClaimTypes.NameIdentifier
            };
        }
Пример #14
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
        }
        public static JwtBearerOptions WithEventsProcessor(this JwtBearerOptions options, JwtBearerEvents eventsProcessor)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }
            if (eventsProcessor == null)
            {
                throw new ArgumentNullException(nameof(eventsProcessor));
            }

            options.Events = eventsProcessor;
            return(options);
        }
Пример #16
0
        internal void ConfigureJwtBearer(JwtBearerOptions jwtOptions)
        {
            jwtOptions.Authority                  = Authority;
            jwtOptions.RequireHttpsMetadata       = RequireHttpsMetadata;
            jwtOptions.BackchannelTimeout         = BackChannelTimeouts;
            jwtOptions.RefreshOnIssuerKeyNotFound = true;
            jwtOptions.SaveToken                  = SaveToken;

            jwtOptions.Events = new JwtBearerEvents
            {
                OnMessageReceived = e =>
                {
                    e.Token = InternalTokenRetriever(e.Request);
                    return(JwtBearerEvents.MessageReceived(e));
                },

                OnTokenValidated       = e => JwtBearerEvents.TokenValidated(e),
                OnAuthenticationFailed = e => JwtBearerEvents.AuthenticationFailed(e),
                OnChallenge            = e => JwtBearerEvents.Challenge(e)
            };

            if (DiscoveryDocumentRefreshInterval.HasValue)
            {
                var parsedUrl = DiscoveryClient.ParseUrl(Authority);

                var httpClient = new HttpClient(JwtBackChannelHandler ?? new HttpClientHandler())
                {
                    Timeout = BackChannelTimeouts,
                    MaxResponseContentBufferSize = 1024 * 1024 * 10 // 10 MB
                };

                var manager = new ConfigurationManager <OpenIdConnectConfiguration>(
                    parsedUrl.Url,
                    new OpenIdConnectConfigurationRetriever(),
                    new HttpDocumentRetriever(httpClient)
                {
                    RequireHttps = RequireHttpsMetadata
                })
                {
                    AutomaticRefreshInterval = DiscoveryDocumentRefreshInterval.Value
                };

                jwtOptions.ConfigurationManager = manager;
            }

            if (JwtBackChannelHandler != null)
            {
                jwtOptions.BackchannelHttpHandler = JwtBackChannelHandler;
            }

            // if API name is set, do a strict audience check for
            if (!string.IsNullOrWhiteSpace(ApiName) && !LegacyAudienceValidation)
            {
                jwtOptions.Audience = ApiName;
            }
            else
            {
                // no audience validation, rely on scope checks only
                jwtOptions.TokenValidationParameters.ValidateAudience = false;
            }

            jwtOptions.TokenValidationParameters.NameClaimType = NameClaimType;
            jwtOptions.TokenValidationParameters.RoleClaimType = RoleClaimType;
            if (TokenDecryptionKey != null)
            {
                jwtOptions.TokenValidationParameters.TokenDecryptionKey = TokenDecryptionKey;
            }
            else if (!string.IsNullOrWhiteSpace(CertificateThumbprint))
            {
                var certStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
                certStore.Open(OpenFlags.ReadOnly);

                var certCollection = certStore.Certificates.Find(X509FindType.FindByThumbprint, CertificateThumbprint, true);
                if (certCollection.Count == 0)
                {
                    throw new Exception("CertificateNotFound");
                }

                var certificate = certCollection[0];
                jwtOptions.TokenValidationParameters.TokenDecryptionKey = new X509SecurityKey(certificate);
            }
            jwtOptions.TokenValidationParameters.RequireSignedTokens = RequireSignedTokens;
            jwtOptions.TokenValidationParameters.ValidateIssuer      = ValidateIssuer;


            if (JwtValidationClockSkew.HasValue)
            {
                jwtOptions.TokenValidationParameters.ClockSkew = JwtValidationClockSkew.Value;
            }

            if (InboundJwtClaimTypeMap != null)
            {
                var handler = new JwtSecurityTokenHandler
                {
                    InboundClaimTypeMap = InboundJwtClaimTypeMap
                };

                jwtOptions.SecurityTokenValidators.Clear();
                jwtOptions.SecurityTokenValidators.Add(handler);
            }
        }
Пример #17
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="services"></param>
        /// <param name="name"></param>
        /// <param name="configuration"></param>
        /// <param name="events"></param>
        public static void AddAzureAdAuthentication(this IServiceCollection services, IConfiguration configuration, JwtBearerEvents events = null, string sectionName = "AzureAdAuth")
        {
            var azureAdAuth = new AzureAdAuth();

            configuration.Bind(sectionName, azureAdAuth);

            services.AddAuthentication(sharedoptions =>
            {
                sharedoptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(options =>
            {
                options.Authority = azureAdAuth.Authority;
                options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
                {
                    ValidAudiences = azureAdAuth.ValidAudiences,
                    ValidIssuers   = azureAdAuth.ValidIssuers
                };

                if (events != null)
                {
                    options.Events = events;
                }
            });

            services.AddScoped <ITokenService, TokenService>();
        }
        public static void AddJwtBearerAuthentication(this IServiceCollection serviceCollection, IConfiguration configuration, Action <JwtBearerOptions> configureOptions = null, JwtBearerEvents bearerEvents = null)
        {
            configuration.GetSection("TokenConfig").Bind(_tokenConfig);
            var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_tokenConfig.TokenSigningKey));

            if (configureOptions == null)
            {
                configureOptions = options =>
                {
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidAudience            = "*",
                        ValidateIssuer           = true,
                        ValidateAudience         = true,
                        ValidateLifetime         = true,
                        ValidateIssuerSigningKey = true,
                        ValidIssuers             = _tokenConfig.TokenIssuers,
                        IssuerSigningKeys        = new[] { signingKey }
                    };

                    if (bearerEvents != null)
                    {
                        options.Events = bearerEvents;
                    }
                    else
                    {
                        options.Events = new JwtBearerEvents
                        {
                            OnMessageReceived = OnMessageReceived,
                            OnTokenValidated  = TokenValidated
                        }
                    };
                };
            }

            serviceCollection.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(configureOptions);
        }
Пример #19
0
        //oauth 2
        public void ConfigureJwtAuthService(IServiceCollection services)
        {
            var audienceConfig       = Configuration.GetSection("Audience");
            var symmetricKeyAsBase64 = audienceConfig["Secret"];
            var signingKey           = JwtSecurityKey.Create(symmetricKeyAsBase64);

            var tokenValidationParameters = new TokenValidationParameters
            {
                // The signing key must match!
                ValidateIssuerSigningKey = true,
                IssuerSigningKey         = signingKey,

                // Validate the JWT Issuer (iss) claim
                ValidateIssuer = true,
                ValidIssuer    = audienceConfig["Iss"],

                // Validate the JWT Audience (aud) claim
                ValidateAudience = true,
                ValidAudience    = audienceConfig["Aud"],

                // Validate the token expiry
                ValidateLifetime = true,

                ClockSkew = TimeSpan.Zero,

                RequireExpirationTime = true,
            };

            var jwtBearerEvents = new JwtBearerEvents
            {
                OnAuthenticationFailed = context =>
                {
                    var err = "";

                    if (context.Exception.GetType() == typeof(SecurityTokenValidationException))
                    {
                        err = "invalid token";
                    }
                    else if (context.Exception.GetType() == typeof(SecurityTokenInvalidIssuerException))
                    {
                        err = "invalid issuer";
                    }
                    else if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                    {
                        err = "token expired";
                    }

                    var resp = new
                    {
                        error  = err,
                        status = 401
                    };

                    context.Response.WriteAsync(JsonConvert.SerializeObject(resp, Formatting.Indented));

                    return(Task.FromResult <object>(0));

                    //return Task.CompletedTask;
                },
                OnTokenValidated = context =>
                {
                    return(Task.CompletedTask);
                },
                OnMessageReceived = context =>
                {
                    var value = context.Request.Headers["Authorization"].ToString();
                    if (!string.IsNullOrEmpty(value) && value.ToLower().Contains("bearer"))
                    {
                        value = value.Trim().Substring(6).Trim();
                    }
                    if (!string.IsNullOrEmpty(value))
                    {
                        context.Token = value;
                    }
                    return(Task.CompletedTask);
                },
                OnChallenge = context =>
                {
                    return(Task.CompletedTask);
                }
            };

            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme    = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(options =>
            {
                options.RequireHttpsMetadata      = false;
                options.TokenValidationParameters = tokenValidationParameters;
                options.Events = jwtBearerEvents;
            });
        }
Пример #20
0
        public static void ConfigureJwt(this IServiceCollection services, IConfiguration configurationRoot,
                                        Func <JwtIssuerOptions, JwtSigningKey> signingKey, JwtBearerEvents jwtBearerEvents = null)
        {
            var jwtAppSettingOptions = configurationRoot.GetSection(nameof(JwtIssuerOptions)).Get <JwtIssuerOptions>();

            var issuerSigningKey = signingKey(jwtAppSettingOptions);

            services.AddSingleton(issuerSigningKey);

            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidIssuer    = jwtAppSettingOptions.Issuer,

                ValidateAudience = true,
                ValidAudience    = jwtAppSettingOptions.Audience,

                ValidateIssuerSigningKey = true,
                IssuerSigningKey         = issuerSigningKey,

                RequireExpirationTime = true,
                ValidateLifetime      = true,

                ClockSkew = TimeSpan.Zero
            };

            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(options =>
            {
                options.TokenValidationParameters = tokenValidationParameters;
                options.Events = jwtBearerEvents ?? new JwtBearerEvents();
            });
        }
        private static void AddAuthenticate(IServiceCollection services)
        {
            var authenticationBuilder = services.AddAuthentication(o =>
            {
                o.DefaultAuthenticateScheme = jwtBearerScheme;
                o.DefaultChallengeScheme    = jwtBearerScheme;
            });

            authenticationBuilder.AddJwtBearer(options =>
            {
                // Forward any requests to cookie scheme that not start with /api to that scheme
                options.ForwardDefaultSelector = ctx => ctx.Request.Path.StartsWithSegments("/api")
                    ? null
                    : cookieScheme;

                //todo: use configurations
                var jwtSetting = JwtSetting.Instance;
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer           = true,
                    ValidateAudience         = true,
                    ValidateLifetime         = true,
                    ValidateIssuerSigningKey = true,
                    ValidIssuer      = jwtSetting.Issuer,
                    ValidAudience    = jwtSetting.Issuer,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSetting.Key))
                };

                var jwtBearerEvents = new JwtBearerEvents();
                options.Events      = jwtBearerEvents;
                //测试用 => 模拟发来的Authorization: "Bearer Token"
                jwtBearerEvents.OnMessageReceived = context =>
                {
                    if (string.IsNullOrWhiteSpace(MockClientRequest.Instance.Token))
                    {
                        return(Task.CompletedTask);
                    }

                    //模拟客户端发来的Bearer Token
                    var theToken = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
                    if (theToken == null)
                    {
                        context.Request.Headers["Authorization"] = "Bearer " + MockClientRequest.Instance.Token;
                    }
                    context.Token = MockClientRequest.Instance.Token;
                    return(Task.CompletedTask);
                };
            });

            authenticationBuilder.AddCookie(cookieScheme, options =>
            {
                // Forward any requests that start with /api to that scheme
                options.ForwardDefaultSelector = ctx => ctx.Request.Path.StartsWithSegments("/api")
                    ? jwtBearerScheme
                    : null;

                //todo: use configurations
                var cookieSetting        = CookieSetting.Instance;
                options.ExpireTimeSpan   = cookieSetting.ExpireTimeSpan;
                options.LoginPath        = cookieSetting.LoginPath;
                options.LogoutPath       = cookieSetting.LogoutPath;
                options.AccessDeniedPath = cookieSetting.AccessDeniedPath;
            });
        }
 private QueryStringJwtBearerEventsWrapper CreateQueryStringJwtBearerEvents(
     JwtBearerEvents inner)
 {
     return(new QueryStringJwtBearerEventsWrapper(inner));
 }
Пример #23
0
 public void WithEventsProcessorShouldValidateInput(JwtBearerOptions options,
                                                    JwtBearerEvents eventsProcessor)
 {
     Assert.Throws <ArgumentNullException>(() => options.WithEventsProcessor(eventsProcessor));
 }
        /// <summary>
        /// 使用 JWT 认证。
        /// </summary>
        /// <param name="app">项目构建器。</param>
        /// <param name="events">认证配置。</param>
        /// <returns></returns>
        public static IApplicationBuilder UseJwtBearer(this IApplicationBuilder app, JwtBearerEvents events)
        {
            if (events is null)
            {
                throw new ArgumentNullException(nameof(events));
            }

            return(app.Use(next =>
            {
                return context =>
                {
                    var receivedContext = new MessageReceivedContext(context);

                    events.MessageReceived(receivedContext);

                    if (string.IsNullOrEmpty(receivedContext.Token))
                    {
#if NET40
                        next.Invoke(context);
                        return;
#else
                        return next.Invoke(context);
#endif
                    }

                    var tokenValidateContext = new TokenValidateContext(receivedContext);

                    events.TokenValidate(tokenValidateContext);

                    if (tokenValidateContext.UserData is null || tokenValidateContext.UserData.Count == 0)
                    {
#if NET40
                        next.Invoke(context);
                        return;
#else
                        return next.Invoke(context);
#endif
                    }

                    var tokenValidatedContext = new TokenValidatedContext(tokenValidateContext);

                    events.TokenValidated(tokenValidatedContext);

                    if (tokenValidatedContext.User?.Identity?.IsAuthenticated ?? false)
                    {
                        context.User = tokenValidatedContext.User;
#if NET40
                        Thread.CurrentPrincipal = tokenValidatedContext.User;
#endif
                    }

#if NET40
                    next.Invoke(context);

                    return;
#else
                    return next.Invoke(context);
#endif
                };
            }));
        }
        public static void ConfigureJwt(this IServiceCollection services, IConfiguration configurationRoot,
                                        Func <JwtIssuerOptions, JwtSigningKey> signingKey, JwtBearerEvents jwtBearerEvents = null)
        {
            var jwtAppSettingOptions = configurationRoot.GetSection(nameof(JwtIssuerOptions)).Get <JwtIssuerOptions>();

            var issuerSigningKey = signingKey(jwtAppSettingOptions);

            services.AddSingleton(issuerSigningKey);

            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidIssuer    = jwtAppSettingOptions.Issuer,

                ValidateAudience = true,
                ValidAudience    = jwtAppSettingOptions.Audience,

                ValidateIssuerSigningKey = true,
                IssuerSigningKey         = issuerSigningKey,

                RequireExpirationTime = true,
                ValidateLifetime      = true,

                ClockSkew = TimeSpan.Zero
            };

            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme    = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(options =>
            {
                options.RequireHttpsMetadata      = false;
                options.TokenValidationParameters = tokenValidationParameters;
                options.Events = new JwtBearerEvents
                {
                    OnMessageReceived = context =>
                    {
                        var task = Task.Run(() =>
                        {
                            if (context.Request.Query.TryGetValue("securityToken", out var securityToken))
                            {
                                context.Token = securityToken.FirstOrDefault();
                            }
                        });

                        return(task);
                    }
                };
            });
        }
Пример #26
0
        //oauth 2
        public void ConfigureJwtAuthService(IServiceCollection services)
        {
            var audienceConfig       = Configuration.GetSection("Audience");
            var symmetricKeyAsBase64 = audienceConfig["Secret"];
            var signingKey           = JwtSecurityKey.Create(symmetricKeyAsBase64);

            var tokenValidationParameters = new TokenValidationParameters
            {
                // The signing key must match!
                ValidateIssuerSigningKey = true,
                IssuerSigningKey         = signingKey,

                // Validate the JWT Issuer (iss) claim
                ValidateIssuer = true,
                ValidIssuer    = audienceConfig["Iss"],

                // Validate the JWT Audience (aud) claim
                ValidateAudience = true,
                ValidAudience    = audienceConfig["Aud"],

                // Validate the token expiry
                ValidateLifetime = true,

                ClockSkew = TimeSpan.Zero,

                RequireExpirationTime = true
            };

            var jwtBearerEvents = new JwtBearerEvents
            {
                OnAuthenticationFailed = context =>
                {
                    return(Task.CompletedTask);
                },
                OnTokenValidated = context =>
                {
                    return(Task.CompletedTask);
                },
                OnMessageReceived = context =>
                {
                    var value = context.Request.Headers["Authorization"].ToString();
                    if (!string.IsNullOrEmpty(value) && value.ToLower().Contains("bearer"))
                    {
                        value = value.Trim().Substring(6).Trim();
                    }
                    if (!string.IsNullOrEmpty(value))
                    {
                        context.Token = value;
                    }
                    return(Task.CompletedTask);
                },
                OnChallenge = context =>
                {
                    return(Task.CompletedTask);
                }
            };

            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme    = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(options =>
            {
                options.RequireHttpsMetadata      = false;
                options.TokenValidationParameters = tokenValidationParameters;
                options.Events = jwtBearerEvents;
            });
        }
Пример #27
0
 protected abstract JwtBearerEvents CreateJwtBearerEvents(JwtBearerEvents inner);
Пример #28
0
        /// <summary>
        /// Adds a JwtBearerOptions and JwtTokenFactory instance to the IServiceCollection
        /// </summary>
        /// <param name="serviceCollection"></param>
        /// <param name="issuer">The Issuer field for the JWTs</param>
        /// <param name="secretKey">The secret key to be used to sign and validate JWTs. Should be big and kept secret</param>
        /// <param name="environment"></param>
        /// <param name="events">Optionally, you can provide an events object so you can handle JWT related events</param>
        public static void AddJwtServices(this IServiceCollection serviceCollection, string issuer, string secretKey, IHostingEnvironment environment, JwtBearerEvents events = null)
        {
            var signingKey         = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey));
            var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);

            serviceCollection.Add(ServiceDescriptor.Singleton(new JwtTokenFactory(issuer, signingCredentials)));
            serviceCollection.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme    = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(o => CreateJwtBearerOptions(o, issuer, signingKey, environment, events));
        }
        internal void ConfigureJwtBearer(JwtBearerOptions jwtOptions)
        {
            jwtOptions.Authority                  = Authority;
            jwtOptions.RequireHttpsMetadata       = RequireHttpsMetadata;
            jwtOptions.BackchannelTimeout         = BackChannelTimeouts;
            jwtOptions.RefreshOnIssuerKeyNotFound = true;
            jwtOptions.SaveToken                  = SaveToken;

            jwtOptions.Events = new JwtBearerEvents
            {
                OnMessageReceived = e =>
                {
                    e.Token = InternalTokenRetriever(e.Request);
                    return(JwtBearerEvents.MessageReceived(e));
                },

                OnTokenValidated       = e => JwtBearerEvents.TokenValidated(e),
                OnAuthenticationFailed = e => JwtBearerEvents.AuthenticationFailed(e),
                OnChallenge            = e => JwtBearerEvents.Challenge(e)
            };

            if (DiscoveryDocumentRefreshInterval.HasValue)
            {
                var parsedUrl = DiscoveryEndpoint.ParseUrl(Authority);

                var httpClient = new HttpClient(JwtBackChannelHandler ?? new HttpClientHandler())
                {
                    Timeout = BackChannelTimeouts,
                    MaxResponseContentBufferSize = 1024 * 1024 * 10 // 10 MB
                };

                var manager = new ConfigurationManager <OpenIdConnectConfiguration>(
                    parsedUrl.Url,
                    new OpenIdConnectConfigurationRetriever(),
                    new HttpDocumentRetriever(httpClient)
                {
                    RequireHttps = RequireHttpsMetadata
                })
                {
                    AutomaticRefreshInterval = DiscoveryDocumentRefreshInterval.Value
                };

                jwtOptions.ConfigurationManager = manager;
            }

            if (JwtBackChannelHandler != null)
            {
                jwtOptions.BackchannelHttpHandler = JwtBackChannelHandler;
            }

            // if API name is set, do a strict audience check for
            if (!string.IsNullOrWhiteSpace(ApiName) && !LegacyAudienceValidation)
            {
                jwtOptions.Audience = ApiName;
            }
            else
            {
                // no audience validation, rely on scope checks only
                jwtOptions.TokenValidationParameters.ValidateAudience = false;
            }

            jwtOptions.TokenValidationParameters.NameClaimType = NameClaimType;
            jwtOptions.TokenValidationParameters.RoleClaimType = RoleClaimType;

            if (JwtValidationClockSkew.HasValue)
            {
                jwtOptions.TokenValidationParameters.ClockSkew = JwtValidationClockSkew.Value;
            }

            if (InboundJwtClaimTypeMap != null)
            {
                var handler = new JwtSecurityTokenHandler
                {
                    InboundClaimTypeMap = InboundJwtClaimTypeMap
                };

                jwtOptions.SecurityTokenValidators.Clear();
                jwtOptions.SecurityTokenValidators.Add(handler);
            }
        }
Пример #30
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddIdentity <IdentityUser, IdentityRole>().AddEntityFrameworkStores <ConduitDbContext>().AddDefaultTokenProviders();

            services.Configure <IdentityOptions>(options =>
            {
                options.User.RequireUniqueEmail = true;
            });

            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
            TokenValidationParameters tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer           = true,
                ValidateAudience         = true,
                ValidateLifetime         = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer      = Configuration["Jwt:Issuer"],
                ValidAudience    = Configuration["Jwt:Issuer"],
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
            };
            JwtBearerEvents events = new JwtBearerEvents()
            {
                OnMessageReceived = context =>
                {
                    string auth = context.Request.Headers["Authorization"];
                    if (auth?.StartsWith("Token ", StringComparison.OrdinalIgnoreCase) ?? false)
                    {
                        context.Request.Headers["Authorization"] = "Bearer " + auth.Substring("Token ".Length).Trim();
                    }
                    return(Task.CompletedTask);
                }
            };

            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme    = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(options =>
            {
                options.TokenValidationParameters = tokenValidationParameters;
                options.Events = events;
                options.IncludeErrorDetails = true;
            })
            .AddJwtBearer("Token", options =>
            {
                options.TokenValidationParameters = tokenValidationParameters;
                options.Events = events;
                options.IncludeErrorDetails = true;
            });

            services.AddDbContext <ConduitDbContext>(options =>
                                                     options.UseSqlServer(Configuration.GetConnectionString("ConduitDB")));

            services.AddMvc();

            services.AddAuthorization(options =>
            {
                options.AddPolicy("ValidUsername", policy =>
                                  policy.Requirements.Add(new ValidUsernameRequirement()));
            });

            services.AddScoped <IAuthorizationHandler, ValidJWTAuthorizationHandler>();

            //Custom services
            services.AddScoped <IArticleService, ArticleService>();
            services.AddScoped <ICommentService, CommentService>();
            services.AddScoped <IProfileService, ProfileService>();
            services.AddScoped <IUserService, UserService>();

            //Custom repositories
            services.AddScoped <IArticleRepository, ArticleRepository>();
            services.AddScoped <IArticleTagsRepository, ArticleTagsRepository>();
            services.AddScoped <ICommentRepository, CommentRepository>();
            services.AddScoped <IFavoriteArticleRepository, FavoriteArticleRepository>();
            services.AddScoped <ITagsRepository, TagsRepository>();
            services.AddScoped <IUserIsFollowingRepository, UserIsFollowingRepository>();
            services.AddScoped <IUserPersonalizationRepository, UserPersonalizationRepository>();
        }