ASP.NET的WebAPI身份Facebook登录 [英] WebApi ASP.NET Identity Facebook login

查看:413
本文介绍了ASP.NET的WebAPI身份Facebook登录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在为asp.net身份的Facebook认证流程,Facebook的誓言对话框追加code,而不是访问令牌REDIRECT_URL以便服务器可以通过<$ C交流这方面的code访问令牌$ C>的http://本地主机?:49164 /登入Facebook的code = ...&放大器;状态= ...

In the facebook authentication flow for asp.net identity, the facebook oath dialog appends a code rather than access token to the redirect_url so that the server can exchange this code for an access token via http://localhost:49164/signin-facebook?code=...&state=....

我的问题是,我的客户是一个移动应用程序,它使用Facebook的SDK,并且马上给了我一个访问令牌。 Facebook表示,使用SDK总是给你一个访问令牌,所以我马上给网页API的访问令牌。我明白这不是很安全,但它甚至有可能?

My problem is that my client is a mobile app which uses the the facebook sdk and that straight away gives me an access token. Facebook says using the sdk always gives you an access token so can I straight away give web api the access token. I understand this is not very secure but is it even possible?

推荐答案

我不知道,如果你终于找到了解决办法,但我试图做一些事情pretty相似,我仍然把件的砌起来。
我曾试图发布此作为,而不是回答的评论,因为我不提供真正的解决方案,但它是太长了。

I don't know if you finally found a solution, but I'm trying to do something pretty similar and I'm still putting the pieces of the puzzle together. I had tried to post this as a comment instead of an answer, as I do not provide a real solution, but it's too long.

显然,所有的WebAPI Owin OAuth的选项是基于浏览器,这是他们需要大量的浏览器重定向不适合原生移动应用(我的情况)的请求。
我仍然在调查和试验,但简要地鸿业太阳在评论他的博客,<一的一个描述href=\"http://blogs.msdn.com/b/webdev/archive/2013/09/20/understanding-security-features-in-spa-template.aspx?PageIndex=2#comments\">http://blogs.msdn.com/b/webdev/archive/2013/09/20/understanding-security-features-in-spa-template.aspx?PageIndex=2#comments ,与Facebook的登录使用Facebook的SDK可以直接通过图形调用/我的端点API进行验证收到的访问令牌。

Apparently all the WebAPI Owin OAuth options are browser based, that is they require lots of browser redirections requests that do not fit a native mobile app (my case). I'm still investigating and experimenting, but as briefly described by Hongye Sun in one of the comments to his blog post, http://blogs.msdn.com/b/webdev/archive/2013/09/20/understanding-security-features-in-spa-template.aspx?PageIndex=2#comments , to login with Facebook the access token received using Facebook SDK can be verified directly by the API making a graph call to the /me endpoint.

通过使用由图调用返回的信息,您可以检查用户是否已经被注册或没有。
最后,我们需要注册的用户,也许用Authentication.SignIn Owin方法,返回将被用于所有后续API调用的承载令牌。

By using the info returned by the graph call, you can check if the user is already registered or not. At the end we need to sign-in the user, maybe using Authentication.SignIn Owin method, returning a bearer token that will be used for all subsequent API calls.

编辑:
其实我听错了,承载令牌上呼吁发出/令牌端点,这在输入接受类似 grant_type =密码&放大器;用户名=爱丽丝和放大器;密码= password123
这里的问题是,我们没有一个密码(这是OAuth的机制的整点),所以我们还能怎么调用/令牌端点?

Actually I got it wrong, the bearer token is issued on calling "/Token" endpoint, which on input accepts something like grant_type=password&username=Alice&password=password123 The problem here is that we do not have a password (that's the whole point of the OAuth mechanism), so how else can we invoke the "/Token" endpoint?

更新:
我终于找到了一个工作解决方案,下面是我不得不添加到现有的类,使其工作:
Startup.Auth.cs

UPDATE: I finally found a working solution and the following is what I had to add to the existing classes to make it work: Startup.Auth.cs

public partial class Startup
{
    /// <summary>
    /// This part has been added to have an API endpoint to authenticate users that accept a Facebook access token
    /// </summary>
    static Startup()
    {
        PublicClientId = "self";

        //UserManagerFactory = () => new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
        UserManagerFactory = () => 
        {
            var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
            userManager.UserValidator = new UserValidator<ApplicationUser>(userManager) { AllowOnlyAlphanumericUserNames = false };
            return userManager;
        };

        OAuthOptions = new OAuthAuthorizationServerOptions
        {
            TokenEndpointPath = new PathString("/Token"),
            Provider = new ApplicationOAuthProvider(PublicClientId, UserManagerFactory),
            AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
            AllowInsecureHttp = true
        };

        OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
        OAuthBearerOptions.AccessTokenFormat = OAuthOptions.AccessTokenFormat;
        OAuthBearerOptions.AccessTokenProvider = OAuthOptions.AccessTokenProvider;
        OAuthBearerOptions.AuthenticationMode = OAuthOptions.AuthenticationMode;
        OAuthBearerOptions.AuthenticationType = OAuthOptions.AuthenticationType;
        OAuthBearerOptions.Description = OAuthOptions.Description;
        OAuthBearerOptions.Provider = new CustomBearerAuthenticationProvider();            
        OAuthBearerOptions.SystemClock = OAuthOptions.SystemClock;
    }

    public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }

    public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }

    public static Func<UserManager<ApplicationUser>> UserManagerFactory { get; 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)
    {
        [Initial boilerplate code]

        OAuthBearerAuthenticationExtensions.UseOAuthBearerAuthentication(app, OAuthBearerOptions);

        [More boilerplate code]
    }
}

public class CustomBearerAuthenticationProvider : OAuthBearerAuthenticationProvider
{
    public override Task ValidateIdentity(OAuthValidateIdentityContext context)
    {
        var claims = context.Ticket.Identity.Claims;
        if (claims.Count() == 0 || claims.Any(claim => claim.Issuer != "Facebook" && claim.Issuer != "LOCAL_AUTHORITY" ))
            context.Rejected();
        return Task.FromResult<object>(null);
    }
}

进入的AccountController我添加了以下行动

Into AccountController I added the following action

        [HttpPost]
        [AllowAnonymous]
        [Route("FacebookLogin")]
        public async Task<IHttpActionResult> FacebookLogin(string token)
        {
            [Code to validate input...]
            var tokenExpirationTimeSpan = TimeSpan.FromDays(14);            
            ApplicationUser user = null;    
            // Get the fb access token and make a graph call to the /me endpoint    
            // Check if the user is already registered
            // If yes retrieve the user 
            // If not, register it  
            // Finally sign-in the user: this is the key part of the code that creates the bearer token and authenticate the user
            var identity = new ClaimsIdentity(Startup.OAuthBearerOptions.AuthenticationType);
            identity.AddClaim(new Claim(ClaimTypes.Name, user.Id, null, "Facebook"));
                // This claim is used to correctly populate user id
                identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id, null, "LOCAL_AUTHORITY"));
            AuthenticationTicket ticket = new AuthenticationTicket(identity, new AuthenticationProperties());            
            var currentUtc = new Microsoft.Owin.Infrastructure.SystemClock().UtcNow;
            ticket.Properties.IssuedUtc = currentUtc;
            ticket.Properties.ExpiresUtc = currentUtc.Add(tokenExpirationTimeSpan);            
            var accesstoken = Startup.OAuthBearerOptions.AccessTokenFormat.Protect(ticket); 
            Authentication.SignIn(identity);

            // Create the response
            JObject blob = new JObject(
                new JProperty("userName", user.UserName),
                new JProperty("access_token", accesstoken),
                new JProperty("token_type", "bearer"),
                new JProperty("expires_in", tokenExpirationTimeSpan.TotalSeconds.ToString()),
                new JProperty(".issued", ticket.Properties.IssuedUtc.ToString()),
                new JProperty(".expires", ticket.Properties.ExpiresUtc.ToString())
            );
            var json = Newtonsoft.Json.JsonConvert.SerializeObject(blob);
            // Return OK
            return Ok(blob);
        }

就是这样。我发现与经典/令牌端点响应的唯一区别是承载令牌略短和到期及发行日期是在UTC而不是在格林尼治标准​​时间(至少在我的机器上)。

That's it. The only difference I found with the classic /Token endpoint response is that the bearer token is slightly shorter and the expiration and issue dates are in UTC instead that in GMT (at least on my machine).

我希望这有助于!

这篇关于ASP.NET的WebAPI身份Facebook登录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆