Rob*_*Rob 4 c# facebook asp.net-web-api bearer-token asp.net-core
我目前正在 Xamarin.Forms 中构建我的第一个移动应用程序。该应用程序有一个 facebook 登录,在用户登录后,我存储 facebook 令牌,因为我想将它用作不记名令牌来验证针对 API 的任何进一步请求。
该 API 是一个 .NET core 2.0 项目,我正在努力使身份验证正常工作。
在我的 Xamarin.Forms 应用程序中,使用以下代码将 facebook 令牌设置为不记名令牌;
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", UserToken);
Run Code Online (Sandbox Code Playgroud)
据我所知,这正确地在请求的标头中设置了承载令牌。我和我的一位同事谈过这个问题,他告诉我看一下 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();
}
}
Run Code Online (Sandbox Code Playgroud)
但是,当我使用邮递员执行请求并测试一切是否正常工作时,我收到以下错误;
InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found.
Run Code Online (Sandbox Code Playgroud)
我在这里做错了什么?
编辑:同时,如果忙于寻找解决方案。在 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();
}
Run Code Online (Sandbox Code Playgroud)
我创建了一个 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);
}
}
Run Code Online (Sandbox Code Playgroud)
我现在遇到的问题是我不知道从哪里获取 IHttpContextAccessor。这是以某种方式注入的吗?我是否走在解决这个问题的正确道路上?
我最终创建了自己的 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);
}
}
Run Code Online (Sandbox Code Playgroud)
添加以下类,其中将包含代表用户的配置;
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; }
}
Run Code Online (Sandbox Code Playgroud)
最后但并非最不重要的一点是,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;
}
}
Run Code Online (Sandbox Code Playgroud)
这将验证来自请求的 Facebook 令牌作为不记名令牌,并由 Facebook 检查它是否仍然有效。
归档时间: |
|
查看次数: |
6813 次 |
最近记录: |