2017-10-14 64 views
1

我目前在Xamarin.Forms中構建了我的第一個移動應用程序。該應用程序有一個Facebook登錄,並在用戶登錄後,我存儲的是Facebook標記,因爲我想用它作爲承載令牌來驗證任何針對API的進一步請求。如何在asp.net核心2中驗證facebook web api

該API是一個.NET核心2.0項目,我很努力獲得認證工作。

在我的Xamarin.Forms應用程序中,facebook令牌被設置爲帶有以下代碼的載體令牌;

_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", UserToken); 

據我所知,這正確地設置請求標頭中的不記名令牌。 我已經跟我的一位同事談過這件事了,他讓我看看Identityserver4應該支持這一點。但就目前而言,我決定不這樣做,因爲對我來說,在這一刻,實施這個是開銷。所以我決定留下這個想法,使用Facebook令牌作爲不記名令牌並驗證它。

對我來說,下一步是找到一種方法來驗證傳入的持票人令牌與Facebook以檢查它是否(仍然)有效。 所以我爲我的API項目配置了啓動,如下所示;

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.AddAuthentication(o => 
     { 
      o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; 
      o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; 
     }).AddFacebook(o => 
     { 
      o.AppId = "MyAppId"; 
      o.AppSecret = "MyAppSecret"; 
     }); 

     services.AddMvc(); 
    } 

    // 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(); 
     } 

     //Enable authentication 
     app.UseAuthentication(); 

     //Enable support for default files (eg. default.htm, default.html, index.htm, index.html) 
     app.UseDefaultFiles(); 

     //Configure support for static files 
     app.UseStaticFiles(); 

     app.UseMvc(); 
    } 
} 

但是,當我使用郵遞員做請求和測試,如果一切正常工作,我收到以下錯誤;

InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found. 

我在這裏做錯了什麼?

編輯: 在同時,如果一直忙着試圖找到解決方案。在Google上閱讀很多內容之後,似乎添加AuthorizationHandler是目前的方式。從那裏開始,我可以向Facebook發送請求以檢查令牌是否有效。我已將以下代碼添加到我的ConfigureServices方法中;

public void ConfigureServices(IServiceCollection services) 
    { 
     //Other code 

     services.AddAuthorization(options => 
     { 
      options.AddPolicy("FacebookAuthentication", policy => policy.Requirements.Add(new FacebookRequirement())); 
     }); 

     services.AddMvc(); 
    } 

而且我創建了一個FacebookRequirement,它可以幫助我處理政策;

public class FacebookRequirement : AuthorizationHandler<FacebookRequirement>, IAuthorizationRequirement 
    { 
     private readonly IHttpContextAccessor contextAccessor; 
     public FacebookRequirement(IHttpContextAccessor contextAccessor) 
     { 
      this.contextAccessor = contextAccessor; 
     } 

     protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, FacebookRequirement requirement) 
     { 
      //var socialConfig = new SocialConfig{Facebook = new SocialApp{AppId = "MyAppId", AppSecret = "MyAppSecret" } }; 
      //var socialservice = new SocialAuthService(socialConfig); 

      //var result = await socialservice.VerifyFacebookTokenAsync() 
      var httpContext = contextAccessor.HttpContext; 

      if (httpContext != null && httpContext.Request.Headers.ContainsKey("Authorization")) 
      { 
       var token = httpContext.Request.Headers.Where(x => x.Key == "Authorization").ToList(); 
      } 

      context.Succeed(requirement); 

      return Task.FromResult(0); 
     } 
    } 

現在我遇到的問題是,我不知道在哪裏得到IHttpContextAccessor。這是被注入某種方式?我甚至在正確的道路上解決這個問題?

回答

0

我結束了創建我自己的AuthorizationHandler驗證使用承載令牌對Facebook的傳入的請求後。將來我可能會開始使用Identityserver處理多種登錄類型。但現在Facebook已經足夠。

以下是未來參考的解決方案。

首先創建一個FacebookRequirement類繼承AuthorizationHandler;

public class FacebookRequirement : AuthorizationHandler<FacebookRequirement>, IAuthorizationRequirement 
    { 
     protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, FacebookRequirement requirement) 
     { 
      var socialConfig = new SocialConfig { Facebook = new SocialApp { AppId = "<FacebookAppId>", AppSecret = "<FacebookAppSecret>" } }; 
      var socialservice = new SocialAuthService(socialConfig); 

      var authorizationFilterContext = context.Resource as AuthorizationFilterContext; 
      if (authorizationFilterContext == null) 
      { 
       context.Fail(); 
       return Task.FromResult(0); 
      } 

      var httpContext = authorizationFilterContext.HttpContext; 
      if (httpContext != null && httpContext.Request.Headers.ContainsKey("Authorization")) 
      { 
       var authorizationHeaders = httpContext.Request.Headers.Where(x => x.Key == "Authorization").ToList(); 
       var token = authorizationHeaders.FirstOrDefault(header => header.Key == "Authorization").Value.ToString().Split(' ')[1]; 

       var user = socialservice.VerifyTokenAsync(new ExternalToken { Provider = "Facebook", Token = token }).Result; 
       if (!user.IsVerified) 
       { 
        context.Fail(); 
        return Task.FromResult(0); 
       } 

       context.Succeed(requirement); 
       return Task.FromResult(0); 
      } 

      context.Fail(); 
      return Task.FromResult(0); 
     } 
    } 

添加以下的類將包含結構的代表所述用戶;

public class SocialConfig 
    { 
     public SocialApp Facebook { get; set; } 
    } 

    public class SocialApp 
    { 
     public string AppId { get; set; } 
     public string AppSecret { get; set; } 
    } 

    public class User 
    { 
     public Guid Id { get; set; } 
     public string SocialUserId { get; set; } 
     public string Email { get; set; } 
     public bool IsVerified { get; set; } 
     public string Name { get; set; } 

     public User() 
     { 
      IsVerified = false; 
     } 
    } 

    public class ExternalToken 
    { 
     public string Provider { get; set; } 
     public string Token { get; set; } 
    } 

最後但並非最不重要的,SocialAuthService類將處理與Facebook的要求;

public class SocialAuthService 
    { 
     private SocialConfig SocialConfig { get; set; } 

     public SocialAuthService(SocialConfig socialConfig) 
     { 
      SocialConfig = socialConfig; 
     } 

     public async Task<User> VerifyTokenAsync(ExternalToken exteralToken) 
     { 
      switch (exteralToken.Provider) 
      { 
       case "Facebook": 
        return await VerifyFacebookTokenAsync(exteralToken.Token); 
       default: 
        return null; 
      } 
     } 

     private async Task<User> VerifyFacebookTokenAsync(string token) 
     { 
      var user = new User(); 
      var client = new HttpClient(); 

      var verifyTokenEndPoint = string.Format("https://graph.facebook.com/me?access_token={0}&fields=email,name", token); 
      var verifyAppEndpoint = string.Format("https://graph.facebook.com/app?access_token={0}", token); 

      var uri = new Uri(verifyTokenEndPoint); 
      var response = await client.GetAsync(uri); 

      if (response.IsSuccessStatusCode) 
      { 
       var content = await response.Content.ReadAsStringAsync(); 
       dynamic userObj = (Newtonsoft.Json.Linq.JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(content); 

       uri = new Uri(verifyAppEndpoint); 
       response = await client.GetAsync(uri); 
       content = await response.Content.ReadAsStringAsync(); 
       dynamic appObj = (Newtonsoft.Json.Linq.JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(content); 

       if (appObj["id"] == SocialConfig.Facebook.AppId) 
       { 
        //token is from our App 
        user.SocialUserId = userObj["id"]; 
        user.Email = userObj["email"]; 
        user.Name = userObj["name"]; 
        user.IsVerified = true; 
       } 

       return user; 
      } 
      return user; 
     } 
    } 

這將驗證來自請求的Facebook令牌作爲載體令牌,與Facebook一起檢查它是否仍然有效。

+0

糾正我,如果我錯了,但這意味着,在您的服務的每一個請求,你向Facebook發出一個請求。這聽起來不太有效。 – Stilgar

0

嘗試_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer ", UserToken);

承載添加一個空格

+0

我不認爲這會解決問題。因爲即使我測試槽郵遞員時,我得到的錯誤 – Rob

相關問題