使用ASP.NET Core 2.1的Facebook Auth:OAuth“ Facebook平台”“ invalid_code”“已使用此授权代码。”

时间:2018-07-01 20:48:48

标签: asp.net facebook authentication oauth-2.0 asp.net-core-2.0

我已经在stackoverflow上阅读了其他框架的类似问题,但没有一个涉及如何使用ASP.NET Core 2.1解决此问题。我假设某处我将需要修改由库生成的访问令牌,但是我看不到它的简单钩子。

导航到标有[Authorize]的控制器/操作后,错误产生以下异常:

Exception: OAuth token endpoint failure: Status: BadRequest;Headers: Cache-    Control: no-store
Connection: keep-alive
Date: Sun, 01 Jul 2018 20:26:11 GMT
Pragma: no-cache
WWW-Authenticate: OAuth "Facebook Platform" "invalid_code" "This authorization code has been used."
Strict-Transport-Security: max-age=15552000;  x-fb-trace-id: FUP+X7GzCHR
x-fb-rev: 4066065
facebook-api-version: v2.6
Access-Control-Allow-Origin: *
X-FB-Debug: 97aI6xVBbJLooeNj3qmNCw9NFifMBvYire/pA0R6dCH5BqWcJ9Vc9rJK+KWvwiNiTXV4PX5ASLbEkbCGgqtCmg==
;Body: {"error":{"message":"This authorization code has been used.","type":"OAuthException","code":100,"fbtrace_id":"FUP+X7GzCHR"}};
Unknown location
Exception: An error was encountered while handling the remote login.
Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler+<HandleRequestAsync>d__12.MoveNext()

我的Startup.cs如下:

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 IServiceProvider ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<FacebookIdentityContext>();
    //services.AddDataProtection().PersistKeysToAzureBlobStorage(new Uri(Configuration["Blob:Uri"])).ProtectKeysWithDpapi();
    services.AddCors(options =>
    {

        options.AddPolicy("AllowAll", p => p.AllowAnyOrigin()
                                            .AllowAnyMethod()
                                            .AllowAnyHeader());
    });

    services.AddIdentity<FacebookUser, IdentityRole<int>>().AddEntityFrameworkStores<FacebookIdentityContext>().AddDefaultTokenProviders();
    services.AddAuthentication().AddFacebook(fb =>
    {
        fb.AppId = Configuration["Facebook:AppId"];
        fb.AppSecret = Configuration["Facebook:AppSecret"];
        fb.CallbackPath += "/";
    });
    services.AddMvc().AddControllersAsServices();

    Container container = new Container();
    container.Configure(config =>
    {
        CosmosDataToken graphToken = new CosmosDataToken(new Uri(Configuration["GraphDB:Uri"]), Configuration["GraphDB:Key"], Configuration["GraphDB:Database"], Configuration["GraphDB:DocumentCollection"]);
        config.For<CosmosDataToken>().Add(graphToken).Named("Graph");
        config.For<IBrandDataAdapter>().Use<BrandDataAdapter>().Ctor<CosmosDataToken>().Named("Graph");
        config.For<IBrandBusinessLogic>().Use<BrandBusinessLogic>();
        config.Populate(services);
        config.For<IContainer>().Use(container);
    });
    return container.GetInstance<IServiceProvider>();
}

// 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.UseBrowserLink();
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }
    app.UseAuthentication();
    app.UseStaticFiles();
    app.UseCors("AllowAll");

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

}

}

AccounController.cs:

[Route("[controller]/[action]")]
public class AccountController : Controller
{
    [HttpGet]
    public IActionResult SignIn()
    {
        var redirectUrl = Url.Action(nameof(HomeController.Index), "Home");
        return Challenge(
            new AuthenticationProperties { RedirectUri = redirectUrl },
            FacebookDefaults.AuthenticationScheme);
    }
    [HttpGet]

    public IActionResult Login(string returnUrl)
    {
        return Challenge(
            new AuthenticationProperties { RedirectUri = returnUrl }, FacebookDefaults.AuthenticationScheme);
    }
}

根据要求:Raw Stack Trace(2018年7月9日)

System.Exception: An error was encountered while handling the remote login. ---> System.Exception: OAuth token endpoint failure: Status: BadRequest;Headers:     Cache-Control: no-store

Connection: keep-alive

Date: Tue, 10 Jul 2018 02:07:33 GMT

Pragma: no-cache

WWW-Authenticate: OAuth "Facebook Platform" "invalid_code" "This authorization code has been used."

Strict-Transport-Security: max-age=15552000; preload

x-fb-trace-id: GGIG00tEoLq

x-fb-rev: 4083489

facebook-api-version: v2.6

Access-Control-Allow-Origin: *

X-FB-Debug: oRwbzflr375r3JhjSp0V1K1iP3+vI5m/kHUCsr5CPHwHv68Waz4eydZ8cw5cTCCT2KUo6Z8la42syKtNPuWfxQ==

;Body: {"error":{"message":"This authorization code has been used.","type":"OAuthException","code":100,"fbtrace_id":"GGIG00tEoLq"}};

   --- End of inner exception stack trace ---

   at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1.<HandleRequestAsync>d__12.MoveNext()

--- End of stack trace from previous location where exception was thrown ---

   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()

 at     System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.<Invoke>d__6.MoveNext()

--- End of stack trace from previous location where exception was thrown ---

   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()

   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.<Invoke>d__7.MoveNext()

和IIS日志:

2018-07-10 02:07:33 ::1 GET /signin-facebook/ code=AQACzBL6QlPjzfEBoB2L9LEbMXgdxw3KNgcBc-8fv2RGHAtfa9bGCqWZ-efFgEPv_mx1Xaphi6z0Ok6cNGDArIWiwdtIw_tB2r6EaQ7TyEsov5fajemTgYZtsgJXEOtpOo0YQmBDROIMtaKEAREsJFeN3eR3QYqEedadgSRikCB-gFVKCSalPXVQubHGzPRQHOl16u-zNNe4sJJlBX8G0LZeJ7tziCnIiexfTB_zBWvFrgjggfUPtlFV2VLWLxH55O3xD1sZxY2xFTy01P4Tb4ENAurvAh2techvnV4uDobSyrSVoylGSKEqTHdalENlqKU&state=CfDJ8Fal1oNbU75Jg6-R34J8E0YhIDy-BtCBqI_xTclwY43ARUtMiTWDmco_N7wJNTbUoHedtAe0yVBR2r9sV_sOTayIgaJEkRuqWyuO0i5Yh6vB7pbUX4krFRcwIzDbVSBGxPwBzQSOqtLPoY8KlKjmN70sooi_fQqq3OIcFynOe8UVd-mMtodbu3fdOz0kVpdO-khCscC-R4p78IJiWzqAN_Xsd_MR4ihTKbWSBfGRVreU 44392 - ::1 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/64.0.3282.140+Safari/537.36+Edge/17.17134 - 500 0 0 245

编辑2018年7月12日: 可以在以下网址找到具有相同错误的完整示例:https://github.com/jlind0/TestFacebookAuth

1 个答案:

答案 0 :(得分:2)

我弄清楚了你的问题。您的AccountController出问题了。当您致电Challenge时,用户将重定向到Facebook,并在成功登录后返回。当用户返回时,其凭证将添加IdentityConstants.ExternalScheme。在这里,您还需要使用SignIn来调用IdentityConstants.ApplicationScheme。因此,您需要一个回调方法来处理此问题。

这就是您的AccountController

中需要的内容
[HttpGet]
public IActionResult SignIn()
{
    var redirectUrl = Url.Action(nameof(HomeController.Index), "Home");
    return Login(redirectUrl);
}

[HttpGet]
public IActionResult Login(string returnUrl)
{
    var redirectUrl = Url.Action(nameof(AccountController.LoginCallback), "Account", new { returnUrl = returnUrl });

    return Challenge(
        new AuthenticationProperties { RedirectUri = redirectUrl, }, FacebookDefaults.AuthenticationScheme);
}

[HttpGet]
public async Task<IActionResult> LoginCallback(string returnUrl)
{
    var authenticateResult = await HttpContext.AuthenticateAsync(IdentityConstants.ExternalScheme);

    await HttpContext.SignInAsync(IdentityConstants.ApplicationScheme, new System.Security.Claims.ClaimsPrincipal(authenticateResult.Ticket.Principal.Identity));

    return LocalRedirect(returnUrl);
}

但是我强烈建议您使用该模板作为用户管理器。