具有Facebook访问令牌的MVC 5 Web API无需Register Cookie即可注册到RegisterExternal

Parveenkhtkr

设置:仅具有Web API的新MVC5项目。添加了Facebook AppId和Secret。
我可以Token通过传递用户名和密码来端点获取Web API的令牌然后使用该令牌进行进一步调用。

但是我想在iOS应用中的Facebook SDK的帮助下注册新用户。我正在使用Facebook SDK来获取访问令牌。(假设此时,我有一个访问令牌)。

我知道的下一件事是api/Account/RegisterExternal通过在Authorization标头中传递此令牌来调用端点Bearer [Access Token]但这会导致500服务器错误。

我想我知道原因,Cookie丢失了。我使用来自Fidler的cookie进行了相同的调用,并且效果很好。(通过转到ExternalLogins端点提供的URL来接收Cookie 。)由于缺少Cookie await Authentication.GetExternalLoginInfoAsync();,RegisterExternal操作内将返回null。

// POST api/Account/RegisterExternal
[OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("RegisterExternal")]
public async Task<IHttpActionResult> RegisterExternal(RegisterExternalBindingModel model)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    var info = await Authentication.GetExternalLoginInfoAsync();
    if (info == null)
    {
        return InternalServerError();
    }

    var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };

    IdentityResult result = await UserManager.CreateAsync(user);
    if (!result.Succeeded)
    {
        return GetErrorResult(result);
    }

    result = await UserManager.AddLoginAsync(user.Id, info.Login);
    if (!result.Succeeded)
    {
        return GetErrorResult(result);
    }
    return Ok();
}

我不想对Web API进行3次调用以请求外部登录,然后转到该URL并在Web浏览器中对Facebook访问令牌进行身份验证,然后使用该访问令牌和需要收集的Cookie调用RegisterExternal端点在这些通话之间。

正如我说的,除了Facebook ID之外,我没有更改模板中的任何内容。代码仍然如下。

public partial class Startup
{
    public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }

    public static string PublicClientId { get; private set; }

    // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
    public void ConfigureAuth(IAppBuilder app)
    {
        // Configure the db context and user manager to use a single instance per request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

        // Enable the application to use a cookie to store information for the signed in user
        // and to use a cookie to temporarily store information about a user logging in with a third party login provider
        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

        // Configure the application for OAuth based flow
        PublicClientId = "self";
        OAuthOptions = new OAuthAuthorizationServerOptions
        {
            TokenEndpointPath = new PathString("/Token"),
            Provider = new ApplicationOAuthProvider(PublicClientId),
            AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
            AllowInsecureHttp = true
        };

        // Enable the application to use bearer tokens to authenticate users
        app.UseOAuthBearerTokens(OAuthOptions);

        app.UseFacebookAuthentication(
            appId: "xxxxxxxxxxxxxxx",
            appSecret: "xxxxxxxxxxxxxxxxxxxxxxxx");
    }
}

据我所知,Web API不需要Cookie,当我从Token终结点计算机获取本地令牌时,它看起来是正确的,但是为什么在进行ExternalRegisterWebApiConfig类时它首先需要Cookie,所以看起来像这样,并且应该config.SuppressDefaultHostAuthentication();避免任何Cookie的需求

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
        // Configure Web API to use only bearer token authentication.
        config.SuppressDefaultHostAuthentication();
        config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));

        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}

我不知道是否遗漏了这里。.我的意图是不需要在本机iOS应用中使用Web浏览器来获取令牌。那就是Facebook SDK来获取访问令牌,并使用该调用RegisterExternal来获取本地令牌并创建该用户身份。

我做了家庭作业,但仍然坚持这种想法。感激不尽!

Parveenkhtkr

我误以为它接受带有cookie的Social Token!它不直接接受任何外部令牌。

问题是……MVC 5正在为我们处理所有事情,即从社交媒体收集令牌并对其进行验证/处理。之后,它将生成一个本地令牌。

RegisterExternal方法还需要维护cookie,而解决方案则不需要。

我写了一篇博客文章,将详细解释在下面添加了直接答案。我的目标是使其融入并感觉到默认MVC Web API的“登录/注册”流程的组成部分,以确保其易于理解。

通过以下解决方案后,Authorize属性必须如下所示才能工作,否则您将获得Unauthorized响应。

[Authorize]
[HostAuthentication(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ExternalBearer)]
[HostAuthentication(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ApplicationCookie)]

使用ExternalBearer,如果你希望只允许令牌使用API,使用ApplicationCookie,如果你希望只允许登录cookie的使用API,即从一个网站。如果您要同时使用两者的API,请同时使用两者。

将此动作添加到 AccountController.cs

// POST api/Account/RegisterExternalToken
[OverrideAuthentication]
[AllowAnonymous]
[Route("RegisterExternalToken")]
public async Task<IHttpActionResult> RegisterExternalToken(RegisterExternalTokenBindingModel model)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    ExternalLoginData externalLogin = await ExternalLoginData.FromToken(model.Provider, model.Token);

    if (externalLogin == null)
    {
        return InternalServerError();
    }

    if (externalLogin.LoginProvider != model.Provider)
    {
        Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
        return InternalServerError();
    }

    ApplicationUser user = await UserManager.FindAsync(new UserLoginInfo(externalLogin.LoginProvider,
        externalLogin.ProviderKey));

    bool hasRegistered = user != null;
    ClaimsIdentity identity = null;
    IdentityResult result;

    if (hasRegistered)
    {
        identity = await UserManager.CreateIdentityAsync(user, OAuthDefaults.AuthenticationType);
        IEnumerable<Claim> claims = externalLogin.GetClaims();
        identity.AddClaims(claims);
        Authentication.SignIn(identity);
    }
    else
    {
        user = new ApplicationUser() { Id = Guid.NewGuid().ToString(), UserName = model.Email, Email = model.Email };

        result = await UserManager.CreateAsync(user);
        if (!result.Succeeded)
        {
            return GetErrorResult(result);
        }

        var info = new ExternalLoginInfo()
        {
            DefaultUserName = model.Email,
            Login = new UserLoginInfo(model.Provider, externalLogin.ProviderKey)
        };

        result = await UserManager.AddLoginAsync(user.Id, info.Login);
        if (!result.Succeeded)
        {
            return GetErrorResult(result);
        }

        identity = await UserManager.CreateIdentityAsync(user, OAuthDefaults.AuthenticationType);
        IEnumerable<Claim> claims = externalLogin.GetClaims();
        identity.AddClaims(claims);
        Authentication.SignIn(identity);
    }

    AuthenticationTicket ticket = new AuthenticationTicket(identity, new AuthenticationProperties());
    var currentUtc = new Microsoft.Owin.Infrastructure.SystemClock().UtcNow;
    ticket.Properties.IssuedUtc = currentUtc;
    ticket.Properties.ExpiresUtc = currentUtc.Add(TimeSpan.FromDays(365));
    var accessToken = Startup.OAuthOptions.AccessTokenFormat.Protect(ticket);
    Request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);

    // Create the response building a JSON object that mimics exactly the one issued by the default /Token endpoint
    JObject token = new JObject(
        new JProperty("userName", user.UserName),
        new JProperty("id", user.Id),
        new JProperty("access_token", accessToken),
        new JProperty("token_type", "bearer"),
        new JProperty("expires_in", TimeSpan.FromDays(365).TotalSeconds.ToString()),
        new JProperty(".issued", currentUtc.ToString("ddd, dd MMM yyyy HH':'mm':'ss 'GMT'")),
        new JProperty(".expires", currentUtc.Add(TimeSpan.FromDays(365)).ToString("ddd, dd MMM yyyy HH:mm:ss 'GMT'"))
    );
    return Ok(token);
}

将此辅助方法添加到ExternalLoginData的辅助区域中的类中AccountController.cs

public static async Task<ExternalLoginData> FromToken(string provider, string accessToken)
{
    string verifyTokenEndPoint = "", verifyAppEndpoint = "";

    if (provider == "Facebook")
    {
        verifyTokenEndPoint = string.Format("https://graph.facebook.com/me?access_token={0}", accessToken);
        verifyAppEndpoint = string.Format("https://graph.facebook.com/app?access_token={0}", accessToken);
    }
    else if (provider == "Google")
    {
        return null; // not implemented yet
        //verifyTokenEndPoint = string.Format("https://www.googleapis.com/oauth2/v1/tokeninfo?access_token={0}", accessToken);
    }
    else
    {
        return null;
    }

    HttpClient client = new HttpClient();
    Uri uri = new Uri(verifyTokenEndPoint);
    HttpResponseMessage response = await client.GetAsync(uri);
    ClaimsIdentity identity = null;
    if (response.IsSuccessStatusCode)
    {
        string content = await response.Content.ReadAsStringAsync();
        dynamic iObj = (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);

        identity = new ClaimsIdentity(OAuthDefaults.AuthenticationType);

        if (provider == "Facebook")
        {
            if (appObj["id"] != Startup.facebookAuthOptions.AppId)
            {
                return null;
            }

            identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, iObj["id"].ToString(), ClaimValueTypes.String, "Facebook", "Facebook"));

        }
        else if (provider == "Google")
        {
            //not implemented yet
        }
    }

    if (identity == null)
        return null;

    Claim providerKeyClaim = identity.FindFirst(ClaimTypes.NameIdentifier);

    if (providerKeyClaim == null || String.IsNullOrEmpty(providerKeyClaim.Issuer) || String.IsNullOrEmpty(providerKeyClaim.Value))
        return null;

    if (providerKeyClaim.Issuer == ClaimsIdentity.DefaultIssuer)
        return null;

    return new ExternalLoginData
    {
        LoginProvider = providerKeyClaim.Issuer,
        ProviderKey = providerKeyClaim.Value,
        UserName = identity.FindFirstValue(ClaimTypes.Name)
    };
}

最后RegisterExternalTokenBindingModel是动作所使用的

public class RegisterExternalTokenBindingModel
{
    [Required]
    [Display(Name = "Email")]
    public string Email { get; set; }

    [Required]
    [Display(Name = "Token")]
    public string Token { get; set; }

    [Required]
    [Display(Name = "Provider")]
    public string Provider { get; set; }
}

是的,我们在注册时将电子邮件和令牌详细信息一起传递,这不会导致您在使用Twitter时更改代码,因为Twitter不向用户提供电子邮件。我们验证令牌来自我们的应用程序。一旦电子邮件注册,被黑客入侵或其他人的令牌无法用于更改电子邮件或获取该电子邮件的本地令牌,因为无论发送的电子邮件是什么,它将始终为所传递的社交令牌的实际用户返回本地令牌。

RegisterExternalToken 端点通过两种方式来获取令牌,即注册用户并发送本地令牌,或者如果用户已经注册,则发送令牌。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

MVC5无需使用System.Web即可读取配置值

来自分类Dev

无需登录即可访问Facebook Graph API

来自分类Dev

MVC .NET cookie身份验证系统通过令牌身份验证访问Web Api

来自分类Dev

RESTful Web服务+ Spring Security:具有访问令牌的API服务?

来自分类Dev

MVC 5,Web API和Owin

来自分类Dev

升级到MVC 5和Web API 2后,如何使我的Web API应用再次运行?

来自分类Dev

升级到MVC 5和Web API 2后,如何使我的Web API应用再次运行?

来自分类Dev

使用承载令牌的MVC 5 Identity 2和Web API 2授权和调用api

来自分类Dev

将Angle和.net核心Web API安全地集成到现有的MVC 5应用中

来自分类Dev

无需调试即可工作的ASP.NET 5 Web服务器

来自分类Dev

无需路由器即可访问Web服务器

来自分类Dev

ASP.NET 5(vNext)/ Web API / OAuth / OpenID /令牌/ Cookie /我真正需要什么?

来自分类Dev

为同时具有Web API和常规MVC控制器的项目实现基于令牌的身份验证

来自分类Dev

MVC 5 Web API-使用API密钥

来自分类Dev

具有OWIN OAuth承载令牌的Web Api 2

来自分类Dev

防伪令牌+ Web API(-MVC)

来自分类Dev

生成具有角色的身份用户(从Web API到MVC应用程序)

来自分类Dev

[Facebook Graph API]:如何获取具有特定范围的测试用户访问令牌

来自分类Dev

支持CORS的MVC Web API 5升级

来自分类Dev

MVC5 Web API和依赖注入

来自分类Dev

如何使用Asp MVC 5使用基于Json的Web Api?

来自分类Dev

将Web API Cookie用作MVC Cookie

来自分类Dev

将Web API Cookie用作MVC Cookie

来自分类Dev

升级到ASP.NET MVC 5和Web API 2后如何解析nuget DLL地狱

来自分类Dev

升级到ASP.NET MVC 5和Web API 2后如何解析nuget DLL地狱

来自分类Dev

具有Web Audio API的HTML5音频-在Firefox中不起作用

来自分类Dev

具有Web API Windows身份验证的angularjs html5应用程序

来自分类Dev

无需注册即可访问世界各地的树莓派

来自分类Dev

WEB API 2:在oauth RegisterExternal(facebook)期间获取配置文件数据

Related 相关文章

  1. 1

    MVC5无需使用System.Web即可读取配置值

  2. 2

    无需登录即可访问Facebook Graph API

  3. 3

    MVC .NET cookie身份验证系统通过令牌身份验证访问Web Api

  4. 4

    RESTful Web服务+ Spring Security:具有访问令牌的API服务?

  5. 5

    MVC 5,Web API和Owin

  6. 6

    升级到MVC 5和Web API 2后,如何使我的Web API应用再次运行?

  7. 7

    升级到MVC 5和Web API 2后,如何使我的Web API应用再次运行?

  8. 8

    使用承载令牌的MVC 5 Identity 2和Web API 2授权和调用api

  9. 9

    将Angle和.net核心Web API安全地集成到现有的MVC 5应用中

  10. 10

    无需调试即可工作的ASP.NET 5 Web服务器

  11. 11

    无需路由器即可访问Web服务器

  12. 12

    ASP.NET 5(vNext)/ Web API / OAuth / OpenID /令牌/ Cookie /我真正需要什么?

  13. 13

    为同时具有Web API和常规MVC控制器的项目实现基于令牌的身份验证

  14. 14

    MVC 5 Web API-使用API密钥

  15. 15

    具有OWIN OAuth承载令牌的Web Api 2

  16. 16

    防伪令牌+ Web API(-MVC)

  17. 17

    生成具有角色的身份用户(从Web API到MVC应用程序)

  18. 18

    [Facebook Graph API]:如何获取具有特定范围的测试用户访问令牌

  19. 19

    支持CORS的MVC Web API 5升级

  20. 20

    MVC5 Web API和依赖注入

  21. 21

    如何使用Asp MVC 5使用基于Json的Web Api?

  22. 22

    将Web API Cookie用作MVC Cookie

  23. 23

    将Web API Cookie用作MVC Cookie

  24. 24

    升级到ASP.NET MVC 5和Web API 2后如何解析nuget DLL地狱

  25. 25

    升级到ASP.NET MVC 5和Web API 2后如何解析nuget DLL地狱

  26. 26

    具有Web Audio API的HTML5音频-在Firefox中不起作用

  27. 27

    具有Web API Windows身份验证的angularjs html5应用程序

  28. 28

    无需注册即可访问世界各地的树莓派

  29. 29

    WEB API 2:在oauth RegisterExternal(facebook)期间获取配置文件数据

热门标签

归档