Измените redirectURI и CallbackPath для проверки подлинности AzureAD в веб-приложении .net core 3.1.1

Я создал новое веб-приложение .net core 3.1.1 с фреймворком Razor Pages. При создании приложения я установил аутентификацию по умолчанию как AzureAd. Когда я запускаю приложение, аутентификация работает нормально. Сгенерированный файл appsettings выглядит так:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "myDomain",
    "TenantId": "myTenantId",
    "ClientId": "myClientId",
    "CallbackPath": "/signin-oidc"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

Я создал в своем приложении новый контроллер, который выглядит очень просто, примерно так:

namespace WebApplication1.Controllers
{
    public class AccountController : Controller
    {
        [HttpGet]
        public void SignIn()
        {
           //here comes the logic which checks in what role is the logged User
           //the role management stuff will be implemented in the app
        }
    }
}

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

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
            .AddAzureAD(options => Configuration.Bind("AzureAd", options));
        services.AddMvc(options =>
        {
            options.EnableEndpointRouting = false;
        });
        services.AddRazorPages().AddMvcOptions(options =>{});
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();
            endpoints.MapControllers();
        });

        app.UseMvc(routes =>
       {
            routes.MapRoute(
            name: "default",
            template: "{controller=Account}/{action=SignIn}");
       });
    }
}

Я хотел бы иметь возможность изменить AzureAd / CallbackPath на что-то другое, чем «/ signin-oidc», например. Я хочу изменить его на Аккаунт / Вход. Затем я хотел бы перехватить вызов обратного вызова из лазурного и на основе зарегистрированного адреса электронной почты пользователя я хотел бы изменить токен, чтобы добавить некоторые системные роли и сделать перенаправление на соответствующую страницу панели мониторинга на основе роли пользователя. Панель управления для администратора и клиента может быть разной.

Поэтому я попытался изменить "CallbackPath": "/Account/SignIn", а также обновил RedirectURI в Azure:  RedirectURI в Azure

Затем я снова запускаю приложение, устанавливаю точку останова в void SignIn(), снова вошел в систему, и вместо того, чтобы нажимать /Account/SignIn, меня просто перенаправили на главную страницу the https://localhost:44321. Я также попытался вручную запустить https://localhost:44321/Account/SignIn в браузере и увидел следующее сообщение об ошибке:

An unhandled exception occurred while processing the request.
Exception: OpenIdConnectAuthenticationHandler: message.State is null or empty.

введите здесь описание изображения

Я попытался проверить, есть ли что-то в документация, но я не нашел ничего полезного. Есть идеи о том, что мне делать, чтобы он работал? Ваше здоровье

РЕДАКТИРОВАТЬ:

Я также использую Microsoft.AspNetCore.Authentication.AzureAD.UI framework.


person GoldenAge    schedule 25.04.2020    source источник


Ответы (2)


CallbackPath - это путь, по которому сервер будет перенаправлять во время аутентификации. Он автоматически обрабатывается самим промежуточным программным обеспечением OIDC, что означает, что мы не можем управлять логикой, создав новый контроллер / действие и установив для него CallbackPath. Ниже представлен общий процесс:

Во время аутентификации весь процесс контролируется промежуточным программным обеспечением OpenID Connect, после того как пользователь проверит учетные данные на странице входа в Azure, Azure Ad перенаправит пользователя обратно на URL-адрес перенаправления вашего приложения, который установлен в конфигурации OIDC, чтобы вы могли получить код авторизации (если используя поток кода) и завершите процесс аутентификации. После аутентификации пользователь будет перенаправлен на URL-адрес перенаправления.

на основе адреса электронной почты зарегистрированного пользователя я хотел бы изменить токен, чтобы добавить некоторые системные роли и сделать перенаправление на соответствующую страницу панели инструментов в зависимости от роли пользователя. Панель управления для администратора и клиента может быть разной.

Во-первых, вы не можете изменить токен, и вам не нужно его изменять.

Вы можете использовать события уведомлений в OIDC OWIN Middlerware, которые вызывают, чтобы разработчик мог контролировать процесс аутентификации. OnTokenValidated предлагает вам возможность изменить ClaimsIdentity, полученный из входящего токена, вы можете запросить роль пользователя на основе идентификатора пользователя из локальной базы данных и добавить в утверждения пользователя:

 services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
            .AddAzureAD(options => Configuration.Bind("AzureAd", options));


services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
    options.Events = new OpenIdConnectEvents
    {
        OnTokenValidated = ctx =>
        {
            //query the database to get the role

            // add claims
            var claims = new List<Claim>
            {
                new Claim(ClaimTypes.Role, "Admin")
            };
            var appIdentity = new ClaimsIdentity(claims);

            ctx.Principal.AddIdentity(appIdentity);

            return Task.CompletedTask;
        },
    };
});

Затем в контроллере вы можете получить такое утверждение:

var role = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Role)?.Value;

Затем вы можете отфильтровать действия на основе конкретного утверждения.

Если вы хотите перенаправить пользователя на определенный маршрут / страницу после аутентификации, укажите URL-адрес AuthenticationProperties:

if (!User.Identity.IsAuthenticated)
{
    return Challenge(new AuthenticationProperties() { RedirectUri = "/home/redirectOnRole" } , AzureADDefaults.AuthenticationScheme);
}  

И по этому пути вы можете перенаправить пользователя в зависимости от роли пользователя.

person Nan Yu    schedule 27.04.2020
comment
Куда мне поставить if (!User.Identity.IsAuthenticated) { return Challenge(new AuthenticationProperties() { RedirectUri = "/home/redirectOnRole" } , AzureADDefaults.AuthenticationScheme); } из вашего ответа? Пользователь поступает из Microsoft.AspNetCore.Mvc.Razor, поэтому я не уверен, смогу ли я сделать это в промежуточном программном обеспечении? - person GoldenAge; 27.04.2020
comment
Я также использую Microsoft.AspNetCore.Authentication.AzureAD.UI, поэтому перенаправление на страницу входа в AzureAD происходит через эту структуру. - person GoldenAge; 27.04.2020
comment
Я только что попытался добавить await context.HttpContext.ChallengeAsync(AzureADDefaults.AuthenticationScheme, new AuthenticationProperties { RedirectUri = "/contact" }); в OnTokenValidated, но после повторного входа пользователя перенаправление не сработало :( - person GoldenAge; 27.04.2020
comment
Нет, эти коды должны быть одним действием, которое запускает аутентификацию. - person Nan Yu; 28.04.2020
comment
в моем примере кода также используется библиотека Microsoft.AspNetCore.Authentication.AzureAD.UI;. У вас есть два варианта: 1. после аутентификации пользователь будет перенаправлен на страницу индекса, затем вы можете перенаправить пользователя в зависимости от роли пользователя в действии индекса, я предоставил образец кода для того, как добавить заявление о роли выше. - person Nan Yu; 28.04.2020
comment
2. в методе входа на вашу страницу с бритвой используйте return Challenge(new AuthenticationProperties() { RedirectUri = "/home/redirectOnRole" } , AzureADDefaults.AuthenticationScheme);, чтобы вручную установить URL-адрес, пользователь будет перенаправлен на этот URL-адрес после аутентификации, в этом URL-адресе вы можете перенаправить на другие действия в зависимости от роли пользователя. - person Nan Yu; 28.04.2020
comment
Поскольку я использую библиотеку AzureAd.UI, у меня нет собственного метода входа. Когда я создал приложение, частичное представление с именем _LoginPartial было автоматически добавлено t к Pages/Shared и содержит ссылку, которая выглядит следующим образом: <a class="nav-link text-dark" asp-area="AzureAD" asp-controller="Account" asp-action="SignIn">Sign in</a> это означает, что действие входа в систему находится в AzureAD области, которая является частью фреймворка. Есть ли возможность написать какое-то расширение, чтобы я мог сначала запустить действие входа в систему, а затем сделать перенаправление на это, или что вы предлагаете? - person GoldenAge; 28.04.2020
comment
Вы можете перенаправить пользователя в действие индекса, по умолчанию он будет перенаправлять на страницу индекса. В противном случае вам следует отключить глобальный фильтр аутентификации, который добавлен шаблоном, и добавить действие входа в систему для сортировки схемы аутентификации aad, оно автоматически перенаправит пользователя на страницу входа в Razor страницах входа AAD по умолчанию. - person Nan Yu; 28.04.2020
comment
Мате просто хотел сказать ОГРОМНОЕ СПАСИБО! Вы даже не представляете, сколько часов я потратил, пытаясь решить эту проблему! Теперь все работает так, как я хотел :) - person GoldenAge; 28.04.2020
comment
Итак, что бы я сделал, если бы я хотел что-то сделать сразу после аутентификации / входа пользователя в систему? Скажем, например, я хотел записать метку времени, чтобы сохранить время входа пользователя? - person Michael Gervasoni; 24.09.2020
comment
@MichaelGervasoni, в событии OnTokenValidated вы можете выполнить операцию с базой данных - person Nan Yu; 24.09.2020

Благодаря ответу Нан Йо мне удалось установить перенаправление на нужный мне маршрут после входа в систему через AzureAd, и я также удалось сделать перенаправление на нужную страницу в зависимости от роли зарегистрированного пользователя.

Я изменил _LoginPartial на:

@using HighElo.Web.Extensions
<ul class="navbar-nav">
    @if (User.Identity.IsAuthenticated)
    {
        <li class="nav-item">
            <span class="navbar-text text-dark">Logged as: <b>@User.GetEmail()</b></span>
        </li>
        <li class="nav-item">
            <a class="nav-link text-dark" asp-area="AzureAD" asp-controller="Account" asp-action="SignOut">Sign out</a>
        </li>
    }
    else
    {
        <li class="nav-item">

            <a class="nav-link text-dark" href="/Account/SignIn">Sign in</a>
        </li>
    }
</ul>

Я создал новый контроллер в своем корневом каталоге, который выглядит так:

[AllowAnonymous]
public class AccountController : Controller
{
    [Route("Account/SignIn")]
    public IActionResult SignIn()
    {
        if (!User.Identity.IsAuthenticated)
        {
            return Challenge(new AuthenticationProperties() { RedirectUri = "/Account/Callback" }, AzureADDefaults.AuthenticationScheme);
        }

        return Forbid();
    }

    [Authorize]

    public IActionResult Callback()
    {
        if (User.IsInRole("Client"))
        {
            //redirect to the Clients area
            return LocalRedirect("/Clients/Dashboard");
        }
        //here comes other role checks

        return Forbid();
    }
}
person GoldenAge    schedule 28.04.2020