3

我试图寻找与此相关的问题,但找不到任何东西。

我有一个使用 Azure AD B2C 进行身份验证的 ASP.NET Core 1.0 应用程序。签名和注册以及退出工作都很好。当我尝试编辑用户的个人资料时,问题就来了。这是我的 Startup.cs 的样子:

namespace AspNetCoreBtoC
{
    public class Startup
    {
        private IConfigurationRoot Configuration { get; }

        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                            .SetBasePath(env.ContentRootPath)
                            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                            .AddEnvironmentVariables();
            Configuration = builder.Build();
        }

        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<IConfiguration>(Configuration);
            services.AddMvc();
            services.AddAuthentication(
                opts => opts.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            loggerFactory.AddConsole();

            if (env.IsDevelopment())
            {
                loggerFactory.AddDebug(LogLevel.Debug);
                app.UseDeveloperExceptionPage();
            }

            app.UseStaticFiles();

            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AutomaticChallenge = false
            });

            string signUpPolicyId = Configuration["AzureAd:SignUpPolicyId"];
            string signUpCallbackPath = Configuration["AzureAd:SignUpCallbackPath"];
            app.UseOpenIdConnectAuthentication(CreateOidConnectOptionsForPolicy(signUpPolicyId, false, signUpCallbackPath));

            string userProfilePolicyId = Configuration["AzureAd:UserProfilePolicyId"];
            string profileCallbackPath = Configuration["AzureAd:ProfileCallbackPath"];
            app.UseOpenIdConnectAuthentication(CreateOidConnectOptionsForPolicy(userProfilePolicyId, false, profileCallbackPath));

            string signInPolicyId = Configuration["AzureAd:SignInPolicyId"];
            string signInCallbackPath = Configuration["AzureAd:SignInCallbackPath"];
            app.UseOpenIdConnectAuthentication(CreateOidConnectOptionsForPolicy(signInPolicyId, true, signInCallbackPath));

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "Default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }

        private OpenIdConnectOptions CreateOidConnectOptionsForPolicy(string policyId, bool autoChallenge, string callbackPath)
        {
            string aadInstance = Configuration["AzureAd:AadInstance"];
            string tenant = Configuration["AzureAd:Tenant"];
            string clientId = Configuration["AzureAd:ClientId"];
            string redirectUri = Configuration["AzureAd:RedirectUri"];

            var opts = new OpenIdConnectOptions
            {
                AuthenticationScheme = policyId,
                MetadataAddress = string.Format(aadInstance, tenant, policyId),
                ClientId = clientId,
                PostLogoutRedirectUri = redirectUri,
                ResponseType = "id_token",
                TokenValidationParameters = new TokenValidationParameters
                {
                    NameClaimType = "name"
                },
                CallbackPath = callbackPath,
                AutomaticChallenge = autoChallenge
            };

            opts.Scope.Add("openid");

            return opts;
        }
    }
}

这是我的 AccountController,我从这里向中间件发出挑战:

namespace AspNetCoreBtoC.Controllers
{
    public class AccountController : Controller
    {
        private readonly IConfiguration config;

        public AccountController(IConfiguration config)
        {
            this.config = config;
        }

        public IActionResult SignIn()
        {
            return Challenge(new AuthenticationProperties
            {
                RedirectUri = "/"
            },
            config["AzureAd:SignInPolicyId"]);
        }

        public IActionResult SignUp()
        {
            return Challenge(new AuthenticationProperties
            {
                RedirectUri = "/"
            },
            config["AzureAd:SignUpPolicyId"]);
        }

        public IActionResult EditProfile()
        {
            return Challenge(new AuthenticationProperties
            {
                RedirectUri = "/"
            },
            config["AzureAd:UserProfilePolicyId"]);
        }

        public IActionResult SignOut()
        {
            string returnUrl = Url.Action(
                action: nameof(SignedOut),
                controller: "Account",
                values: null,
                protocol: Request.Scheme);
            return SignOut(new AuthenticationProperties
            {
                RedirectUri = returnUrl
            },
            config["AzureAd:UserProfilePolicyId"],
            config["AzureAd:SignUpPolicyId"],
            config["AzureAd:SignInPolicyId"],
            CookieAuthenticationDefaults.AuthenticationScheme);
        }

        public IActionResult SignedOut()
        {
            return View();
        }
    }
}

我试图从 OWIN 示例中对其进行调整。我遇到的问题是,为了编辑配置文件,我必须向负责该操作的 OpenIdConnect 中间件发出挑战。问题是它调用了默认登录中间件(Cookies),它意识到用户已通过身份验证,因此该操作一定是未经授权的,并尝试重定向到 /Account/AccessDenied (即使我什至没有在那条路线上有任何东西),而不是去 Azure AD 按应有的方式编辑配置文件。

有没有人在 ASP.NET Core 中成功实现了用户配置文件编辑?

4

1 回答 1

1

好吧,我终于解决了。我写了一篇关于设置的博客文章,其中包括解决方案:https ://joonasw.net/view/azure-ad-b2c-with-aspnet-core 。问题是 ChallengeBehavior,它必须设置为 Unauthorized,而不是默认值 Automatic。目前无法使用 ChallengeResult 框架来定义它,所以我自己做了一个:

public class MyChallengeResult : IActionResult
{
    private readonly AuthenticationProperties authenticationProperties;
    private readonly string[] authenticationSchemes;
    private readonly ChallengeBehavior challengeBehavior;

    public MyChallengeResult(
        AuthenticationProperties authenticationProperties,
        ChallengeBehavior challengeBehavior,
        string[] authenticationSchemes)
    {
        this.authenticationProperties = authenticationProperties;
        this.challengeBehavior = challengeBehavior;
        this.authenticationSchemes = authenticationSchemes;
    }

    public async Task ExecuteResultAsync(ActionContext context)
    {
        AuthenticationManager authenticationManager =
            context.HttpContext.Authentication;

        foreach (string scheme in authenticationSchemes)
        {
            await authenticationManager.ChallengeAsync(
                scheme,
                authenticationProperties,
                challengeBehavior);
        }
    }
}

对不起这个名字......但是这个可以从控制器操作中返回,并且通过指定 ChallengeBehavior.Unauthorized,我得到了一切正常工作。

于 2016-08-27T19:30:11.460 回答