0

我找到了关于社交登录的非常有用的科尔多瓦示例https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Samples/ 我已经在此示例之上构建了自己的应用程序,我非常坚持奇怪的问题。第一个输出来自示例,第二个来自我的应用程序。我不知道为什么在我的应用程序中使用“Identity.External”身份验证方案而不是“ServerCookie”。这导致身份验证失败。

示例的输出:

Microsoft.AspNetCore.Hosting.Internal.WebHost: Information: Request starting HTTP/1.1 GET http://localhost:54540/signin-facebook?code=***  
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware: Information: AuthenticationScheme: ServerCookie signed in.

并从我的应用程序中输出:

Microsoft.AspNetCore.Hosting.Internal.WebHost: Information: Request starting HTTP/1.1 GET http://localhost:62892/signin-facebook?code=***
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware: Information: AuthenticationScheme: Identity.External signed in.

完整输出:

Microsoft.AspNetCore.Hosting.Internal.WebHost: Information: Request starting HTTP/1.1 GET http://localhost:62892/signin-facebook?code=***
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware: Information: AuthenticationScheme: Identity.External signed in.
Microsoft.AspNetCore.Hosting.Internal.WebHost: Information: Request finished in 1088.8914ms 302 
Microsoft.AspNetCore.Hosting.Internal.WebHost: Information: Request starting HTTP/1.1 GET     http://localhost:62892/connect/authorize?client_id=myClient&redirect_uri=http://localhost:62892/competitions/dashboard&response_type=token&provider=Facebook  
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService: Information: Authorization failed for user: .
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker: Warning: Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
Microsoft.AspNetCore.Mvc.ChallengeResult: Information: Executing ChallengeResult with authentication schemes ().
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware: Information: AuthenticationScheme: ServerCookie was challenged.
Microsoft.AspNetCore.Hosting.Internal.WebHost: Information: Request finished in 45.0627ms 302 
Microsoft.AspNetCore.Hosting.Internal.WebHost: Information: Request starting HTTP/1.1 GET http://localhost:62892/signin?ReturnUrl=%2Fconnect%2Fauthorize%3Fclient_id%3DmyClient%26redirect_uri%3Dhttp%3A%2F%2Flocalhost%3A62892%2Fcompetitions%2Fdashboard%26response_type%3Dtoken%26provider%3DFacebook  
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker: Information: Executing action method FlyingDuck.Web.Controllers.Api.AuthenticationController.SignIn (FlyingDuck.Web) with arguments (/connect/authorize?client_id=myClient&redirect_uri=http://localhost:62892/competitions/dashboard&response_type=token&provider=Facebook) - ModelState is Valid

我的 Startup.cs 文件内容:

namespace MyProject.Web
{
    public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
            if (env.IsDevelopment())
            {
                builder.AddUserSecrets();
            }
            var wwwrootRoot = env.WebRootPath;
            builder.AddEnvironmentVariables();
            Configuration = builder.Build();
        }

        public IConfigurationRoot Configuration { get; }

        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.AddAuthentication(options =>
            {
                options.SignInScheme = "ServerCookie";
            });  
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("MyEntities")));
            services.Configure<PasswordHasherOptions>(options =>
            {
                options.CompatibilityMode = PasswordHasherCompatibilityMode.IdentityV2;
            });
            services.AddScoped(ctx => new MyEntities(Configuration.GetConnectionString("MyEntities")));
            services.AddScoped<ViewRender, ViewRender>();
            services.AddIdentity<ApplicationUser, IdentityRole<Guid>>(
                options =>
                {
                    options.User.RequireUniqueEmail = true;
                    options.Password.RequireUppercase = false;
                    options.Password.RequireDigit = false;
                    options.Password.RequireNonAlphanumeric = false;
                }
                )
                .AddEntityFrameworkStores<ApplicationDbContext, Guid>()
                .AddDefaultTokenProviders();
            services.AddSingleton(factory => new JsonSerializerSettings
            {
                ContractResolver = new CamelCasePropertyNamesContractResolver(),
                TypeNameHandling = TypeNameHandling.All
            });
            services.AddSession();
            services.AddMvc();
            services.AddSignalR(options =>
            {
                options.Hubs.EnableDetailedErrors = true;
                options.Hubs.EnableJavaScriptProxies = false;
            });
            services.AddCors(o => o.AddPolicy("MyPolicy", b =>
            {
                b.AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader();
            }));
            services.AddTransient<IEmailSender, AuthMessageSender>();
            services.AddTransient<ISmsSender, AuthMessageSender>();
            services.AddSingleton<IConfiguration>(Configuration);
            services.AddSingleton<IConnectionManager, ConnectionManager>();
            // This code is responsible for disable redirect on unauthorized request.
            // We don't need this feature. We want to get 401 instead of 302 redirection.
            // http://stackoverflow.com/a/34332290
            services.Configure<IdentityOptions>(options =>
            {
                options.Cookies.ApplicationCookie.AutomaticAuthenticate = true;
                options.Cookies.ApplicationCookie.AutomaticChallenge = false;
                options.Cookies.ApplicationCookie.AuthenticationScheme = "ApplicationCookie";
            });
            var builder = new ContainerBuilder();
            builder.RegisterModule(new ServicesModule(Configuration));
            builder.Populate(services);
            var container = builder.Build();
            return container.Resolve<IServiceProvider>();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            loggerFactory.AddDebug();
            app.UseIdentity();
            app.UseStatusCodePages();
            app.UseWhen(context => context.Request.Path.StartsWithSegments(new PathString("/api")), branch =>
            {
                branch.UseOAuthValidation(new OAuthValidationOptions
                {
                    AutomaticAuthenticate = true,
                    AutomaticChallenge = true
                });
            });
            app.UseWhen(context => !context.Request.Path.StartsWithSegments(new PathString("/api")), branch =>
            {
                branch.UseCookieAuthentication(new CookieAuthenticationOptions
                {
                    AutomaticAuthenticate = true,
                    AutomaticChallenge = true,
                    AuthenticationScheme = "ServerCookie",
                    CookieName = CookieAuthenticationDefaults.CookiePrefix + "ServerCookie",
                    ExpireTimeSpan = TimeSpan.FromMinutes(60),
                    LoginPath = new PathString("/signin"),
                    LogoutPath = new PathString("/signout")
                });
                branch.UseFacebookAuthentication(new FacebookOptions()
                {
                    AppId = "<removed>",
                    AppSecret = "<removed>"
                });

            });
            app.UseOpenIdConnectServer(options =>
            {
                options.Provider = new AuthorizationProvider();
                options.TokenEndpointPath = "/token";
                options.AuthorizationEndpointPath = "/connect/authorize";
                options.LogoutEndpointPath = "/connect/logout";
                options.SigningCredentials.AddEphemeralKey();
                options.ApplicationCanDisplayErrors = true;
                options.AllowInsecureHttp = true;
            });
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
                app.UseBrowserLink();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }
            app.UseStaticFiles();
            app.UseSession();
            app.UseWebSockets();
            app.UseSignalR();
            app.UseMvc(routes =>
            {
                routes.MapRoute("SignalR", "signalr/{*all}");
                routes.MapRoute("Home", "home/{*all}", new { controller = "Home", action = "Index" });
            });
            app.UseMvcWithDefaultRoute();
        }
    }
}

AuthorizationController 内容与示例中相同:

namespace MyProject.Web.Controllers.Api
{
    [EnableCors(policyName: "MyPolicy")]
    public class AuthorizationController : Controller
    {
        public AuthorizationController() {}

        [Authorize, HttpGet("~/connect/authorize"), HttpPost("~/connect/authorize")]
        public IActionResult Authorize()
        {
            var response = HttpContext.GetOpenIdConnectResponse();
            if (response != null)
            {
                return View("Error", response);
            }
            var request = HttpContext.GetOpenIdConnectRequest();
            if (request == null)
            {
                return View("Error", new OpenIdConnectMessage
                {
                    Error = OpenIdConnectConstants.Errors.ServerError,
                    ErrorDescription = "An internal error has occurred"
                });
            }
            return Accept();
        }

        [Authorize, HttpPost("~/connect/authorize/accept")]
        public IActionResult Accept()
        {
            var response = HttpContext.GetOpenIdConnectResponse();
            if (response != null)
            {
                return View("Error", response);
            }
            var request = HttpContext.GetOpenIdConnectRequest();
            if (request == null)
            {
                return View("Error", new OpenIdConnectMessage
                {
                    Error = OpenIdConnectConstants.Errors.ServerError,
                    ErrorDescription = "An internal error has occurred"
                });
            }
            var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme);
            foreach (var claim in HttpContext.User.Claims)
            {
                claim.SetDestinations(OpenIdConnectConstants.Destinations.AccessToken,
                                      OpenIdConnectConstants.Destinations.IdentityToken);
                identity.AddClaim(claim);
            }
            var ticket = new AuthenticationTicket(
                new ClaimsPrincipal(identity),
                new AuthenticationProperties(),
                OpenIdConnectServerDefaults.AuthenticationScheme);
            ticket.SetScopes(new[] {
                /* openid: */ OpenIdConnectConstants.Scopes.OpenId,
                /* email: */ OpenIdConnectConstants.Scopes.Email,
                /* profile: */ OpenIdConnectConstants.Scopes.Profile,
                /* offline_access: */ OpenIdConnectConstants.Scopes.OfflineAccess
            }.Intersect(request.GetScopes()));
            ticket.SetResources("resource_server");
            return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);
        }

        [Authorize]
        [HttpPost("~/connect/authorize/deny")]
        public IActionResult Deny()
        {
            var response = HttpContext.GetOpenIdConnectResponse();
            if (response != null)
            {
                return View("Error", response);
            }
            var request = HttpContext.GetOpenIdConnectRequest();
            if (request == null)
            {
                return View("Error", new OpenIdConnectMessage
                {
                    Error = OpenIdConnectConstants.Errors.ServerError,
                    ErrorDescription = "An internal error has occurred"
                });
            }
            return Forbid(OpenIdConnectServerDefaults.AuthenticationScheme);
        }

        [HttpGet("~/connect/logout")]
        public async Task<IActionResult> Logout(CancellationToken cancellationToken)
        {
            var response = HttpContext.GetOpenIdConnectResponse();
            if (response != null)
            {
                return View("Error", response);
            }
            var identity = await HttpContext.Authentication.AuthenticateAsync(OpenIdConnectServerDefaults.AuthenticationScheme);
            var request = HttpContext.GetOpenIdConnectRequest();
            if (request == null)
            {
                return View("Error", new OpenIdConnectMessage
                {
                    Error = OpenIdConnectConstants.Errors.ServerError,
                    ErrorDescription = "An internal error has occurred"
                });
            }
            return View("Logout", Tuple.Create(request, identity));
        }

        [HttpPost("~/connect/logout")]
        public IActionResult Logout()
        {
            return SignOut("ServerCookie", OpenIdConnectServerDefaults.AuthenticationScheme);
        }

    }
}
4

0 回答 0