【问题标题】:Change redirectURI and CallbackPath for AzureAD authentication in .net core 3.1.1 web app在 .net core 3.1.1 Web 应用程序中更改 AzureAD 身份验证的 redirectURI 和 CallbackPath
【发布时间】:2020-08-09 02:54:24
【问题描述】:

我使用 Razor Pages 框架创建了一个新的 .net core 3.1.1 Web 应用程序。 创建应用程序时,我将默认身份验证设置为 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”的内容,例如。我想将其更改为帐户/登录。然后我想从 azure 捕获回调调用,并根据记录的用户电子邮件地址修改令牌以添加一些系统角色并根据用户角色重定向到相应的仪表板页面。管理员和客户可以有不同的仪表板。

所以我尝试更改 "CallbackPath": "/Account/SignIn" 并在 Azure 中更新了 RedirectURI:

然后我再次运行应用程序,在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.

我试图检查documentation 中是否有任何东西,但我没有发现任何有用的东西。 关于我应该怎么做才能让它发挥作用的任何想法? 干杯

编辑:

我也使用Microsoft.AspNetCore.Authentication.AzureAD.UI 框架。

【问题讨论】:

    标签: c# authentication asp.net-core azure-active-directory asp.net-core-3.1


    【解决方案1】:

    CallbackPath 是服务器在身份验证期间重定向的路径。它由 OIDC 中间件本身自动处理,这意味着我们无法通过创建新的控制器/动作并将 CallbackPath 设置为它来控制逻辑。大致流程如下:

    在身份验证过程中,整个过程由 OpenID Connect 中间件控制,用户在 Azure 的登录页面验证凭据后,Azure Ad 会将用户重定向回 OIDC 配置中设置的应用程序重定向 url,以便您获得授权代码(如果使用代码流)并完成身份验证过程。身份验证后,用户将被重定向到重定向 url。

    基于登录的用户电子邮件地址,我想修改令牌以添加一些系统角色并根据用户角色重定向到相应的仪表板页面。管理员和客户可以有不同的仪表板。

    第一件事是你不能修改令牌,你不需要修改它。

    您可以在 OIDC OWIN 中间件中使用通知事件,该中间件调用以启用开发人员对身份验证过程的控制。 OnTokenValidated 为您提供了修改从传入令牌获得的 ClaimsIdentity 的机会,您可以根据本地数据库中的用户 id 查询用户的角色并添加到用户的声明中:

     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);
    }  
    

    在该路径中,您可以根据用户的角色重定向用户。

    【讨论】:

    • 我应该把你答案中的if (!User.Identity.IsAuthenticated) { return Challenge(new AuthenticationProperties() { RedirectUri = "/home/redirectOnRole" } , AzureADDefaults.AuthenticationScheme); } 放在哪里?用户来自 Microsoft.AspNetCore.Mvc.Razor 所以我不确定我是否可以在中间件中做到这一点?
    • 我也使用Microsoft.AspNetCore.Authentication.AzureAD.UI,所以重定向到 AzureAD 登录页面是通过这个框架发生的
    • 我刚刚尝试将await context.HttpContext.ChallengeAsync(AzureADDefaults.AuthenticationScheme, new AuthenticationProperties { RedirectUri = "/contact" }); 添加到OnTokenValidated,但重新登录用户后重定向不起作用:(
    • 不,代码应该在一个触发身份验证的操作中。
    • @MichaelGervasoni ,在 OnTokenValidated 事件中,可以进行数据库操作
    【解决方案2】:

    感谢Nan Yo 的回答,在我通过 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();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2019-01-14
      • 2020-05-15
      • 2020-10-15
      • 2019-11-30
      • 2012-11-18
      • 2018-07-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多