我目前正在Xamarin.Forms中构建我的第一个移动应用程序。该应用程序具有Facebook登录名,并且在用户登录后,我存储了Facebook令牌,因为我想将其用作承载令牌,以验证针对API的任何其他请求。
该API是一个.NET Core 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。这是以某种方式注入的吗?我什至在解决这个问题的正确道路上吗?
我最终创建了自己的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检查其是否仍然有效。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句