我可以验证使用带有.net后端的本机iOS sdk创建的Facebook jwt令牌吗?

Pro*_*Guy 2 middleware jwt facebook-ios-sdk asp.net-core

我正在使用.net核心web api后端的iOS应用程序上实现Facebook登录.

  1. 我在Facebook上创建了具有客户端ID和密码的应用程序.
  2. 我在我的应用中添加了iOS和网页
  3. iOS应用程序成功连接并获取令牌
  4. 我将app.UseFacebook代码添加到我的startup.cs并使用app id等配置它.
  5. 我将authorize属性添加到我限制访问的操作中
  6. 我使用https get从iOS调用此web api操作,并添加http标头授权承载(我从Facebook获取的令牌)

获取返回状态代码401,就像我的令牌无效一样.我想知道iOS令牌是否也可以用于网页应用程序?我为我的Facebook应用程序配置了这两个.

Pro*_*Guy 6

我不确定这是否是正确的方法,但我的实施工作正常.

工作流程是,

  • iOS应用程序使用facebook sdk获取facebook访问令牌
  • iOS应用程序使用facebook访问令牌在.NET后端创建用户
  • .NET后端验证facebook访问令牌是否有效并下载用户数据
  • .NET后端创建一个jwt承载令牌并将其返回到iOS应用程序
  • iOS应用程序使用Authorization http标头中的jwt bearer标记调用.NET后端

我通过调用https://graph.facebook.com检查Facebook访问令牌是否有效 - 请参阅:任务VerifyAccessToken(字符串电子邮件,字符串accessToken)

AccountController.cs

[AllowAnonymous, HttpPost("[action]")]
public async Task<ActionResult> FacebookAuth([FromBody] ExternalLoginModel model)
{
    try
    {
        await _interactor.VerifyAccessToken(model.Email, model.Token);

        var result = await _interactor.SignInWithFacebook(model.Email);

        return Ok(result);               
    }
    catch (ValidationException ex)
    {
        return BadRequest(ex.Message.ErrorMessage(Strings.ValidationException));
    }
}

[AllowAnonymous, HttpPost("[action]")]
public async Task<ActionResult> CreateAccountWithFacebook(AccountModel account, string token)
{
  try
  {   
     await _interactor.VerifyAccessToken(account.Email, token);

     if (ModelState.IsValid)
     {               
         var result = await _interactor.CreateFacebookLogin(account);

         return Ok(result);
     }

     return BadRequest(ModelState);
  }
  catch (ValidationException ex)
  {
     return BadRequest(ex.Message.ErrorMessage(Strings.ValidationException));
  }
}
Run Code Online (Sandbox Code Playgroud)

调用facebook图形服务以验证访问令牌是否有效

public async Task<FacebookMeResponse> VerifyAccessToken(string email, string accessToken)
{
    if (string.IsNullOrEmpty(accessToken))
    {
        throw new ValidationException("Invalid Facebook token");
    }

    string facebookGraphUrl = "https://graph.facebook.com/me?fields=cover,age_range,first_name,location,last_name,hometown,gender,birthday,email&access_token=" + accessToken;
    WebRequest request = WebRequest.Create(facebookGraphUrl);
    request.Credentials = CredentialCache.DefaultCredentials;

    using (WebResponse response = await request.GetResponseAsync())
    {
        var status = ((HttpWebResponse)response).StatusCode;

        Stream dataStream = response.GetResponseStream();

        StreamReader reader = new StreamReader(dataStream);
        string responseFromServer = reader.ReadToEnd();
        var facebookUser = JsonConvert.DeserializeObject<FacebookMeResponse>(responseFromServer);

        bool valid = facebookUser != null && !string.IsNullOrWhiteSpace(facebookUser.Email) && facebookUser.Email.ToLower() == email.ToLower();
        facebookUser.PublicProfilePhotoUrl = "http://graph.facebook.com/" + facebookUser.Id + "/picture";

        if (!valid)
        {
            throw new ValidationException("Invalid Facebook token");
        }

        return facebookUser;
    }
}
Run Code Online (Sandbox Code Playgroud)

为您的中间件创建一个jwt bearer令牌,iOS应用程序将使用jwt bearer令牌来调用您的.NET apis(它不会使用facebook access_token)

public async Task<FacebookResponse> SignInWithFacebook(string email)
{
    var claims = new List<Claim>();

    var user = await _userManager.FindByEmailAsync(email);

    var identity = new ClaimsIdentity(claims, "oidc");

    var jwtBearerToken= Guid.NewGuid().ToString();
    var properties = new AuthenticationProperties();
    properties.Items.Add(".Token.access_token", jwtBearerToken);

    await _signInManager.SignInAsync(user, properties, "oidc");

    var principal = await _signInManager.CreateUserPrincipalAsync(user);

    var token = new Token();
    token.Key = jwtBearerToken;
    token.Expiry = DateTime.UtcNow.AddMinutes(30);
    token.UserId = user.Id;
    token.TokenType = "FacebookLogin";

    await _tokensRepository.Save(token);
    var result = _signInManager.IsSignedIn(principal);

    return new FacebookResponse("success", result, jwtBearerToken);
}
Run Code Online (Sandbox Code Playgroud)

如果用户不存在,请创建一个用户

public async Task<FacebookResponse> CreateFacebookLogin(AccountModel model)
{   
    User user = await _userManager.FindByEmailAsync(model.Email);

    if (user == null)
    {
        var createResult = await _userManager.CreateAsync(_mapper.Map<AccountModel, User>(model));
        if (!createResult.Succeeded)
        {
           // handle failure..
        }                
    }

    return await SignInWithFacebook(model.Email);   
}
Run Code Online (Sandbox Code Playgroud)

用于对来自facebook图REST服务的响应进行反序列化的类

public class FacebookAgeRange
{
    public int Min { get; set; }
}

public class FacebookMeResponse
{
    public string Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public string Gender { get; set; }
    public FacebookAgeRange AgeRange { get; set; }
    public string PublicProfilePhotoUrl { get; set; }
}

public class FacebookResponse : IResponse
{
    public bool Ok { get; set; }
    public string Message { get; set; }
    public string JwtToken { get; set; }

    public FacebookResponse(string message, bool ok = true, string jwtToken = "")
    {
        this.Message = message;
        this.Ok = ok;
        this.JwtToken = jwtToken;
    }
}
Run Code Online (Sandbox Code Playgroud)