Azure AD B2C与ASP.NET Core - 无法进入编辑个人资料页面

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中实现了用户资料编辑?
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,可以从控制器操作中返回此内容,并且我已经使一切正常工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接