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

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

问题描述

在Facebook的身份验证流程中,facebook oauth对话框将一个代码添加到redirect_url中,以便服务器可以通过 http:/ / localhost:49164 / signin-facebook?code = ...& state = ...

In the facebook authentication flow for asp.net identity, the facebook oauth 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总是给你一个访问令牌,所以我可以直接给web api访问令牌?

My problem is that my client is a mobile app which uses 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?

推荐答案

我不知道你是否终于找到一个解决方案,但我正在尝试做一些非常相似的事情,还在把拼图拼凑在一起。
我曾尝试将此作为评论而不是答案,因为我没有提供真正的解决方案,但是时间太长。

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选项是基于浏览器的,因为它们需要大量不符合本地移动应用程序的浏览器重定向请求(我的情况)。
我还在调查和试验,但正如Hongye Sun在他的博客文章中的一个评论中所述, http://blogs.msdn.com/b/webdev/archive/2013/09/20/understanding -security-features-in-spa-template.aspx?PageIndex = 2#comments ,要通过Facebook登录,使用Facebook SDK接收的访问令牌可以直接通过API对/ me端点进行图表调用。

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.

编辑:
实际上我错了,承载令牌是在/ Token终端上发出的,在这个端点上输入的内容类似于 grant_type = password& username = Alice& password = password123
这里的问题是我们没有密码(这是OAuth机制的整体),那么我们还可以调用/ Token端点?

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,而不是GMT(至少在我的机器上)。

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).

我希望这有帮助!

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

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