Можно ли интегрировать Azure AD B2C в устаревшее приложение .net framework 4.8?

Я хочу интегрировать Azure AD B2C в устаревшее приложение, запрограммированное с помощью .Net Framework v4.8. Дело в том, что я действительно не могу найти в Интернете ничего, что подходило бы для этой структуры.

Я также пробовал решения

Кто-нибудь уже сделал это и может дать мне несколько советов и рекомендаций по интеграции? Спасибо.

Обновлено: ответ Джеффа был именно тем, что мне нужно. Это то же самое, что и в учебнике, упомянутом Панайотисом в комментариях. Посмотрите здесь.

Я почти уверен, что ты сможешь. AAD B2C использует OpenID Connect (или, я думаю, SAML), поэтому, пока вы можете его использовать, вы можете использовать AAD B2C.

juunas 27.05.2024 09:29

Вы пробовали проверять документацию вместо ChatGPT? Azure AD B2C был выпущен до самой .NET Framework 4.8. Несколько библиотек Azure AD появились и исчезли, а сам Azure AD теперь называется Entra.

Panagiotis Kanavos 27.05.2024 09:36

@Panagiotis - конечно, но я придерживался пакетов, которые не мог интегрировать, потому что платформа v4.8 не поддерживалась.

SCH361 27.05.2024 09:38

Проверьте этот вопрос , который, в свою очередь, перенаправляет на руководство по документации и образец ASP.NET Framework, настроенный для использования Azure AD B2C. Из того, как написано это руководство, не ясно, что это не основной проект, но пример кода таковым является.

Panagiotis Kanavos 27.05.2024 09:48

В целом документы Azure будут охватывать больше платформ, чем документы .NET, и для большинства случаев будут содержать готовые примеры. Однако пакеты Azure SDK меняются (относительно) часто, поэтому используемые сегодня имена могут не совпадать с именами в примерах.

Panagiotis Kanavos 27.05.2024 10:00
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
144
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

MSAL — это официальная библиотека Microsoft для интеграции входа в систему OIDC/AD/AD B2C в ваше собственное приложение.

Поддерживается множество различных фреймворков, а также настольные приложения, написанные на WPF: https://learn.microsoft.com/en-us/entra/identity-platform/sample-v2-code?tabs=apptype#desktop

Пример кода для WPF можно найти здесь: https://github.com/Azure-Samples/active-directory-dotnet-native-aspnetcore-v2/tree/master/1.%20Desktop%20app%20calls%20Web% 20API

Однако эти примеры предназначены для AD, обычно в конфигурации MSAL есть опция, разговариваете ли вы с AD, AD B2C или просто с любым другим IDP OpenID Connect. Если у вас есть какие-либо конкретные проблемы с использованием этого кода, я предлагаю открыть для этого специальный вопрос с подробностями + кодом того, что не работает в вашем приложении.

Ответ принят как подходящий

Да, ты можешь. У меня все еще работает приложение ASP.Net Framework MVC, использующее B2C. Вот краткий обзор того, как я добавил B2C к существующему приложению.

Добавьте класс запуска OWIN, следуя инструкциям здесь — https://learn.microsoft.com/en-us/aspnet/aspnet/overview/owin-and-katana/getting-started-with-owin-and-katana# хост-owin-in-iis

В примере, которому я следовал (несколько лет назад), класс с именем Startup был настроен как частичный класс, разделенный между классом запуска Owin в примере (мой — Startup.cs) и файлом с именем Startup.Auth.cs в папке App_Start. (Если бы я все еще мог найти пример, я бы просто дал на него ссылку, но не могу, поэтому включаю соответствующий код.)

Мой Startup.cs выглядит так:

public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        // this controls the claim type that is used to populate User.Identity.Name
        System.Web.Helpers.AntiForgeryConfig.UniqueClaimTypeIdentifier = "emails";
        
        ConfigureAuth(app);
    }
}

Мой Startup.Auth.cs выглядит так (почти полностью из примера):

public partial class Startup
{
    /*
    * Configure the OWIN middleware
    */

    public void ConfigureAuth(IAppBuilder app)
    {
        app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            // ASP.NET web host compatible cookie manager
            CookieManager = new SystemWebChunkingCookieManager()
        });

        app.UseOpenIdConnectAuthentication(
            new OpenIdConnectAuthenticationOptions
            {
                // Generate the metadata address using the tenant and policy information
                MetadataAddress = String.Format(Globals.WellKnownMetadata, Globals.Tenant, Globals.DefaultPolicy),

                // These are standard OpenID Connect parameters, with values pulled from web.config
                ClientId = Globals.ClientId,
                RedirectUri = Globals.RedirectUri,
                PostLogoutRedirectUri = Globals.RedirectUri,

                // Specify the callbacks for each type of notifications
                Notifications = new OpenIdConnectAuthenticationNotifications
                {
                    RedirectToIdentityProvider = OnRedirectToIdentityProvider,
                    AuthorizationCodeReceived = OnAuthorizationCodeReceived,
                    AuthenticationFailed = OnAuthenticationFailed,
                },

                // Specify the claim type that specifies the Name property.
                TokenValidationParameters = new TokenValidationParameters
                {
                    NameClaimType = "emails",
                    ValidateIssuer = false
                },

                // Specify the scope by appending all of the scopes requested into one string (separated by a blank space)
                Scope = $"openid profile offline_access {Globals.ReadTasksScope} {Globals.WriteTasksScope}",

                // ASP.NET web host compatible cookie manager
                CookieManager = new SystemWebCookieManager()
            }
        );
    }

    /*
     *  On each call to Azure AD B2C, check if a policy (e.g. the profile edit or password reset policy) has been specified in the OWIN context.
     *  If so, use that policy when making the call. Also, don't request a code (since it won't be needed).
     */
    private Task OnRedirectToIdentityProvider(RedirectToIdentityProviderNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
    {
        var policy = notification.OwinContext.Get<string>("Policy");

        if (!string.IsNullOrEmpty(policy) && !policy.Equals(Globals.DefaultPolicy))
        {
            notification.ProtocolMessage.Scope = OpenIdConnectScope.OpenId;
            notification.ProtocolMessage.ResponseType = OpenIdConnectResponseType.IdToken;
            notification.ProtocolMessage.IssuerAddress = notification.ProtocolMessage.IssuerAddress.ToLower().Replace(Globals.DefaultPolicy.ToLower(), policy.ToLower());
        }

        return Task.FromResult(0);
    }

    /*
     * Catch any failures received by the authentication middleware and handle appropriately
     */
    private Task OnAuthenticationFailed(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
    {
        notification.HandleResponse();

        // Handle the error code that Azure AD B2C throws when trying to reset a password from the login page
        // because password reset is not supported by a "sign-up or sign-in policy"
        if (notification.ProtocolMessage.ErrorDescription != null && notification.ProtocolMessage.ErrorDescription.Contains("AADB2C90118"))
        {
            // If the user clicked the reset password link, redirect to the reset password route
            notification.Response.Redirect("/Account/ResetPassword");
        }
        else if (notification.ProtocolMessage.ErrorDescription != null && notification.ProtocolMessage.ErrorDescription.Contains("AADB2C90091"))
        {
            notification.Response.Redirect("/Home/Index");
        }
        else if (notification.Exception.Message == "access_denied")
        {
            notification.Response.Redirect("/");
        }
        else
        {
            notification.Response.Redirect("/Home/Error?message = " + notification.Exception.Message);
        }

        return Task.FromResult(0);
    }

    /*
     * Callback function when an authorization code is received
     */
    private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedNotification notification)
    {
        try
        {
            /*
             The `MSALPerUserMemoryTokenCache` is created and hooked in the `UserTokenCache` used by `IConfidentialClientApplication`.
             At this point, if you inspect `ClaimsPrinciple.Current` you will notice that the Identity is still unauthenticated and it has no claims,
             but `MSALPerUserMemoryTokenCache` needs the claims to work properly. Because of this sync problem, we are using the constructor that
             receives `ClaimsPrincipal` as argument and we are getting the claims from the object `AuthorizationCodeReceivedNotification context`.
             This object contains the property `AuthenticationTicket.Identity`, which is a `ClaimsIdentity`, created from the token received from
             Azure AD and has a full set of claims.
             */
            IConfidentialClientApplication confidentialClient = MsalAppBuilder.BuildConfidentialClientApplication(new ClaimsPrincipal(notification.AuthenticationTicket.Identity));

            // Upon successful sign in, get & cache a token using MSAL
            AuthenticationResult result = await confidentialClient.AcquireTokenByAuthorizationCode(Globals.Scopes, notification.Code).ExecuteAsync();
        }
        catch (Exception ex)
        {
            throw new HttpResponseException(new HttpResponseMessage
            {
                StatusCode = HttpStatusCode.BadRequest,
                ReasonPhrase = $"Unable to get authorization code {ex.Message}."
            });
        }
    }
}

У меня есть эти значения в разделе настроек приложения web.config (очевидно, замените их значениями из регистрации приложения):

<add key = "ida:Tenant" value = "tenantname.onmicrosoft.com" />
<add key = "ida:TenantId" value = "hidden" />
<add key = "ida:ClientId" value = "hidden" />
<add key = "ida:ClientSecret" value = "hidden" />
<add key = "ida:AadInstance" value = "https://tenantname.b2clogin.com/tfp/{0}/{1}" />
<add key = "ida:RedirectUri" value = "https://homepageurl" />
<add key = "ida:SignUpSignInPolicyId" value = "b2c_1_susi" />
<add key = "ida:EditProfilePolicyId" value = "b2c_1_edit_profile" />
<add key = "ida:ResetPasswordPolicyId" value = "b2c_1_reset" />

Вы можете увидеть пару мест, где я использую «электронные письма» для заполнения User.Identity.Name. При желании вы можете указать другую претензию.

Спасибо за этот ответ @jefftrotman! Но у меня есть вопрос: как я могу получить атрибуты пользователя из утверждений, содержащихся в Id-Token?

SCH361 29.05.2024 16:51

Взгляните на пример здесь Learn.microsoft.com/en-us/dotnet/api/…

jefftrotman 01.06.2024 02:08

Другие вопросы по теме