Exemplo n.º 1
0
        /// <summary>
        /// Сконфигурировать в случае, когда клиент использует WebForms.
        /// </summary>
        /// <param name="app">Сборщик приложения.</param>
        /// <returns><paramref name="app"/>.</returns>
        public static IAppBuilder WithWebForms(this IAppBuilder app)
        {
            AuthServerConfiguration config = GetConfigurationFor(app);

            config.UseWebForms = true;
            return(TryConfigureAuthServer(app, config));
        }
Exemplo n.º 2
0
        /// <summary>
        /// Установить собственный URL-адрес клиента identity server.
        /// </summary>
        /// <param name="app">Сборщик приложения.</param>
        /// <param name="ownAddress">Собственный URL-адрес клиента identity server.</param>
        /// <returns><paramref name="app"/>.</returns>
        public static IAppBuilder WithOwnAddress(this IAppBuilder app, string ownAddress)
        {
            AuthServerConfiguration config = GetConfigurationFor(app);

            config.OwnAddress = ownAddress;
            return(TryConfigureAuthServer(app, config));
        }
Exemplo n.º 3
0
        /// <summary>
        /// Установить секрет клиента identity server.
        /// </summary>
        /// <param name="app">Сборщик приложения.</param>
        /// <param name="clientSecret">Секрет клиента identity server.</param>
        /// <returns><paramref name="app"/>.</returns>
        public static IAppBuilder WithClientSecret(this IAppBuilder app, string clientSecret)
        {
            AuthServerConfiguration config = GetConfigurationFor(app);

            config.ClientSecret = clientSecret;
            return(TryConfigureAuthServer(app, config));
        }
Exemplo n.º 4
0
        /// <summary>
        /// Установить URI-адрес identity server.
        /// </summary>
        /// <param name="app">Сборщик приложения.</param>
        /// <param name="address">URI-адрес identity server.</param>
        /// <returns><paramref name="app"/>.</returns>
        public static IAppBuilder UseAuthServer(this IAppBuilder app, string address)
        {
            AuthServerConfiguration config = GetConfigurationFor(app);

            config.IdSrvAddress = address;
            return(TryConfigureAuthServer(app, config));
        }
Exemplo n.º 5
0
        /// <summary>
        /// Получить временную конфигурацию, заполняемую между вызовами методов fluent api для данного сборщика прилоежния.
        /// </summary>
        /// <param name="app">Сборщик приложения.</param>
        /// <returns>Временная конфигурация клиента.</returns>
        private static AuthServerConfiguration GetConfigurationFor(IAppBuilder app)
        {
            if (!Configurations.ContainsKey(app))
            {
                Configurations[app] = new AuthServerConfiguration();
            }

            return(Configurations[app]);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Произвести попытку подключить клиента к identity server с текущей временной конфигурацией.
        /// Ничего не делает, если конфигурация ещё не заполнена, то есть
        /// <see cref="AuthServerConfiguration.IsComplete"/> возвращает false.
        /// </summary>
        /// <param name="app">Сборщик приложения.</param>
        /// <param name="config">Временная конфиграция клиента для данного сборщика приложения.</param>
        /// <returns><paramref name="app"/>.</returns>
        private static IAppBuilder TryConfigureAuthServer(IAppBuilder app, AuthServerConfiguration config)
        {
            if (!config.IsComplete)
            {
                return(app);
            }

            // Это нужно для защиты от CSRF-атак
            AntiForgeryConfig.UniqueClaimTypeIdentifier = "sub";

            // А это нужно, чтобы ключи Claims-ов пользователя имели адекыватные названия
            JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary <string, string>();

            app
            .UseCookieAuthentication(new CookieAuthenticationOptions
            {
                // Используем cookie аутентификацию
                AuthenticationType = "Cookies",
                ExpireTimeSpan     = TimeSpan.FromMinutes(14),
            })
            .UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
            {
                // Задаём адрес identity server
                Authority = config.IdSrvAddress,

                // идентификатор данного клиента, можно найти в IS.Clients
                ClientId = config.ClientId,

                // Секрет приложения-клиента
                ClientSecret = config.ClientSecret,

                // адрес, на который перенаправляем после аутентификации, совпадает с соответствующим в IS.Clients
                RedirectUri = config.OwnAddress,

                // токен, который запрашиваем, связано со значением Flows.Hybrid в IS.Clients
                ResponseType = "code id_token token",

                // адрес, на который редиректит после выхода, совпадает с соответствующим в IS.Clients
                PostLogoutRedirectUri      = config.OwnAddress,
                SignInAsAuthenticationType = "Cookies",
                UseTokenLifetime           = false,

                // Фактически обработчики различных событий
                Notifications = new OpenIdConnectAuthenticationNotifications()
                {
                    AuthorizationCodeReceived = async n =>
                    {
                        // use the access token to retrieve claims from userinfo
                        var uriToUserInfo    = new Uri(config.IdSrvAddress + "/connect/userinfo");
                        var userInfoClient   = new UserInfoClient(uriToUserInfo, n.ProtocolMessage.AccessToken);
                        var userInfoResponse = await userInfoClient.GetAsync();

                        string userName = userInfoResponse?.Claims?.FirstOrDefault(c => c.Item1 == "name")?.Item2;

                        if (userName == null)
                        {
                            // n.OwinContext.Authentication.SignOut();
                            return;
                        }

                        // Создаём claims-ы пользователя, которые в дальнейшем будут видны в методах контроллера
                        var id = new ClaimsIdentity(n.AuthenticationTicket.Identity.AuthenticationType);
                        id.AddClaims(n.AuthenticationTicket.Identity.Claims);

                        // имя пользователя (логин)
                        id.AddClaim(new Claim("name", userName));

                        // и id_token (нужен для logout-а)
                        id.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));
                        id.AddClaim(new Claim("access_token", n.ProtocolMessage.AccessToken));
                        n.AuthenticationTicket = new AuthenticationTicket(id, n.AuthenticationTicket.Properties);
                    },

                    // Нам надо обработать событие выхода пользователя
                    RedirectToIdentityProvider = n =>
                    {
                        // Это взято из примера: https://identityserver.github.io/Documentation/docsv2/overview/mvcGettingStarted.html
                        if (n.ProtocolMessage.RequestType == Microsoft.IdentityModel.Protocols.OpenIdConnectRequestType.LogoutRequest)
                        {
                            // Вот тут нам нужен id_token, который мы добавляли в claims-ы пользователя чуть выше
                            var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token");

                            if (idTokenHint != null)
                            {
                                n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
                            }
                        }

                        return(Task.FromResult(0));
                    },

                    // Исправляет баг, см. https://github.com/IdentityServer/IdentityServer3/issues/542
                    AuthenticationFailed = n =>
                    {
                        if (n.Exception.Message.Contains("IDX21323"))
                        {
                            n.SkipToNextMiddleware();
                        }

                        return(Task.FromResult(0));
                    },
                },
            });

            if (config.UseWebForms)
            {
                app.UseStageMarker(PipelineStage.Authenticate);
            }

            /* Api может пригодиться в будущем, на всякий случай оставил, чтобы не затерялось в истории комитов
             *
             * app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
             * {
             *  Authority = "https://localhost:44363/identity",
             *  RequiredScopes = new[] { "api1" },
             *  DelayLoadMetadata = true,
             *
             *  ClientId = "api1",
             *  ClientSecret = "secret"
             * });*/

            return(app);
        }