在onredirecttoidentityprovider上将asp.net转换为asp.net核心问题

时间:2018-12-15 04:19:26

标签: c# asp.net-mvc asp.net-core asp.net-core-2.0 asp.net-core-2.1

最近,我们已将项目从asp.net迁移到asp.net core,该项目在asp.net中运行良好,我们遵循了Microsoft的迁移文档,将“ asp.net迁移到asp.net core”,并且不幸的是,经过相应修改后,启动类中的OnRedirectToIdentityProvider方法无法在质询调用(来自控制器)上工作。如果有人帮助我弄清楚我的代码哪里有问题,那将是很好的。我已经在同一个问题上讨论了一段时间了。预先感谢。

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.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            //Add a strongly-typed options class to DI
            services.Configure<AuthOptions>(Configuration.GetSection("Authentication"));



            services.AddAuthentication(opt => {
                opt.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                opt.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;

            })
            .AddCookie("MiddleWareCookie")
                .AddOpenIdConnect(options => Configuration.Bind("Authentication", options));

            services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
            {

                options.Authority = Configuration["Authentication:Authority"];
                options.ClientId= Configuration["Authentication:ClientId"];
                options.ClientSecret= Configuration["Authentication:ClientSecret"];



                options.TokenValidationParameters = new TokenValidationParameters
                {
                    // Instead of using the default validation (validating against a single issuer value, as we do in
                    // line of business apps), we inject our own multitenant validation logic
                    ValidateIssuer = false,

                    // If the app is meant to be accessed by entire organizations, add your issuer validation logic here.
                    //IssuerValidator = (issuer, securityToken, validationParameters) => {
                    //    if (myIssuerValidationLogic(issuer)) return issuer;
                    //}
                };

                options.Events = new OpenIdConnectEvents
                {

                    OnRedirectToIdentityProvider = (context) =>
                    {
                        object obj = null;
                        var request = context.Request;

                        if (context.HttpContext.Items.TryGetValue("Authority", out obj))
                        {
                            string authority = obj as string;
                            if (authority != null)
                            {
                                context.ProtocolMessage.IssuerAddress = authority;
                            }
                        }
                        //string appBaseUrl = context.Request.Scheme + "://" + context.Request.Host + context.Request.PathBase;
                        string appBaseUrl = @"https://localhost:44359/";//UriHelper.BuildAbsolute(request.Scheme, request.Host, request.PathBase);
                        Debug.WriteLine($"appBaseUrl: {appBaseUrl}");
                        context.ProtocolMessage.PostLogoutRedirectUri = appBaseUrl;
                        context.ProtocolMessage.Prompt = "select_account";
                        context.ProtocolMessage.Resource =  Configuration["Authentication:AzureResourceManagerIdentifier"];
                        return Task.FromResult(0);
                    },

                    OnAuthorizationCodeReceived = async (context) =>
                    {
                        var request = context.HttpContext.Request;
                        var currentUri = UriHelper.BuildAbsolute(request.Scheme, request.Host, request.PathBase, request.Path);
                        var credential = new ClientCredential(context.Options.ClientId, context.Options.ClientSecret);
                        string tenantId = context.Principal.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;

                        //Comment
                        Debug.WriteLine($"tenantID: {tenantId}");
                        // Revisit
                        string signedInUserUniqueName = context.Principal.FindFirst(ClaimTypes.Name).Value.Split('#')[context.Principal.FindFirst(ClaimTypes.Name).Value.Split('#').Length - 1];
                        //Comment
                        Debug.WriteLine($"tenantID: {signedInUserUniqueName}");

                        var tokenCache = new ADALTokenCache(signedInUserUniqueName);
                        tokenCache.Clear();

                        // revisit
                        AuthenticationContext authContext = new AuthenticationContext(string.Format("https://login.microsoftonline.com/{0}", tenantId), tokenCache);
                        // var items = authContext.TokenCache.ReadItems().ToList();

                        // revisit
                        AuthenticationResult result = await authContext.AcquireTokenByAuthorizationCodeAsync(
                             context.ProtocolMessage.Code, new Uri(currentUri), credential);

                        //Tell the OIDC middleware we got the tokens, it doesn't need to do anything
                        context.HandleCodeRedemption(result.AccessToken, result.IdToken);

                    },

                    OnTokenValidated = (context) => {
                           string issuer = context.Principal.FindFirst("iss").Value;
                        if (issuer != null)
                        {
                            if (!issuer.StartsWith("https://sts.windows.net/"))
                                throw new SecurityTokenValidationException();
                        }


                        return Task.FromResult(0);

                    },

                    OnTicketReceived = context =>
                    {
                        // If your authentication logic is based on users then add your logic here
                        return Task.CompletedTask;
                    },
                    OnAuthenticationFailed = context =>
                    {
                        context.Response.Redirect("/Error");
                        context.HandleResponse(); // Suppress the exception
                        return Task.CompletedTask;
                    },
                    // If your application needs to do authenticate single users, add your user validation below.
                    //OnTokenValidated = context =>
                    //{
                    //    return myUserValidationLogic(context.Ticket.Principal);
                    //}
                };
            });

            services.AddMvc()
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/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.UseCookiePolicy();

            app.UseAuthentication();

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

订阅控制器方法

HttpContext.Items.Add("Authority", string.Format(_authOptions.Authority + "OAuth2/Authorize", _directoryId));

                Dictionary<string, string> dict = new Dictionary<string, string>();
                dict["prompt"] = "select_account";

                var userIdentity = new ClaimsIdentity(User.Claims, "login");

                ClaimsPrincipal principal = new ClaimsPrincipal(userIdentity);

                await HttpContext.AuthenticateAsync("MiddleWareCookie");

1 个答案:

答案 0 :(得分:0)

我看到两件事可以解释为什么未根据您的控制器代码调用OnRedirectToIdentityProvider

  • 您正在调用AuthenticateAsync方法,您的问题表明您正在调用Challenge;
  • 您指的是Cookie身份验证方案(MiddleWareCookie),我认为您的目的是触发OpenID Connect登录。

我相信您需要将HttpContext.AuthenticateAsync("MiddleWareCookie")替换为HttpContext.ChallengeAsync()才能触发OIDC登录请求。

我看到的另一个潜在问题是,您在AddAuthentication方法中将DefaultScheme设置为CookieAuthenticationDefaults.AuthenticationScheme,但是cookie身份验证方案的名称是MiddleWareCookie 。这两个需要同步。