2017-10-14 63 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

相关问题