如何在 asp.net 核心 2 中验证 facebook web api
How to authenticate facebook web api in asp.net core 2
我目前正在 Xamarin.Forms 中构建我的第一个移动应用程序。该应用程序有一个 facebook 登录名,在用户登录后我存储了 facebook 令牌,因为我想将它用作 bearer-token 来验证针对 API.[=17 的任何进一步请求=]
API 是一个 .NET core 2.0 项目,我正在努力使身份验证正常工作。
在我的 Xamarin.Forms 应用程序中,Facebook 令牌设置为 bearer-token,代码如下;
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", UserToken);
据我所知,这会在请求的 headers 中正确设置不记名令牌。
我已经和我的一位同事谈过这个,他告诉我看一下应该支持这个的 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 上阅读了大量内容后,似乎添加授权处理程序是目前的方法。从那里我可以向 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。这是以某种方式注入的吗?我是否在解决这个问题的正确道路上?
我最终创建了自己的 AuthorizationHandler 以使用不记名令牌验证针对 facebook 的传入请求。将来我可能会开始使用 Identityserver 来处理多种登录类型。但目前facebook已经足够了。
下面是解决方案,供以后参考。
首先创建一个 FacebookRequirement
class 继承自 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);
}
}
添加以下 classes,其中将包含代表用户的配置;
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
class 将处理 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 会检查它是否仍然有效。
我目前正在 Xamarin.Forms 中构建我的第一个移动应用程序。该应用程序有一个 facebook 登录名,在用户登录后我存储了 facebook 令牌,因为我想将它用作 bearer-token 来验证针对 API.[=17 的任何进一步请求=]
API 是一个 .NET core 2.0 项目,我正在努力使身份验证正常工作。
在我的 Xamarin.Forms 应用程序中,Facebook 令牌设置为 bearer-token,代码如下;
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", UserToken);
据我所知,这会在请求的 headers 中正确设置不记名令牌。 我已经和我的一位同事谈过这个,他告诉我看一下应该支持这个的 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 上阅读了大量内容后,似乎添加授权处理程序是目前的方法。从那里我可以向 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。这是以某种方式注入的吗?我是否在解决这个问题的正确道路上?
我最终创建了自己的 AuthorizationHandler 以使用不记名令牌验证针对 facebook 的传入请求。将来我可能会开始使用 Identityserver 来处理多种登录类型。但目前facebook已经足够了。
下面是解决方案,供以后参考。
首先创建一个 FacebookRequirement
class 继承自 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);
}
}
添加以下 classes,其中将包含代表用户的配置;
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
class 将处理 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 会检查它是否仍然有效。