Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/31.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在ASP.NET WebApi 2中实现移动应用程序的外部身份验证_C#_Asp.net_Facebook_Asp.net Web Api_Login - Fatal编程技术网

C# 在ASP.NET WebApi 2中实现移动应用程序的外部身份验证

C# 在ASP.NET WebApi 2中实现移动应用程序的外部身份验证,c#,asp.net,facebook,asp.net-web-api,login,C#,Asp.net,Facebook,Asp.net Web Api,Login,我正在尝试构建一个API(使用ASP.NET WebApi),该API将被学校项目的本地移动应用程序使用。(我不关心/开发移动应用程序,这个责任落在其他成员身上) 我现在需要实现基于令牌的Facebook登录。关于如何在基于浏览器的应用程序中实现这一功能,有很多教程可供参考(这非常简单,而且大部分都是内置的),但我不认为这会在本机应用程序中起作用。我不明白的是重定向是如何工作的 根据这一点,我的服务器不需要专门处理任何事情。我不明白这是怎么回事?Facebook的代币将如何处理 另外,我应该实现

我正在尝试构建一个API(使用ASP.NET WebApi),该API将被学校项目的本地移动应用程序使用。(我不关心/开发移动应用程序,这个责任落在其他成员身上) 我现在需要实现基于令牌的Facebook登录。关于如何在基于浏览器的应用程序中实现这一功能,有很多教程可供参考(这非常简单,而且大部分都是内置的),但我不认为这会在本机应用程序中起作用。我不明白的是重定向是如何工作的

根据这一点,我的服务器不需要专门处理任何事情。我不明白这是怎么回事?Facebook的代币将如何处理

另外,我应该实现令牌处理的哪一部分,我真的找不到WebApi外部登录身份验证的好文档

无论如何,如果有人能告诉我发生的令牌交换的确切流程以及ASP.NET默认实现的内容,那将非常有用

另外,我最大的困惑是我不明白Facebook返回的代币将如何处理

  • 我假设令牌将返回到客户端(移动应用程序),如何在服务器上访问它
  • 如何从facebook的令牌创建本地令牌? 这些都是通过ASP.NET内部/自动神奇地完成的吗
  • 很抱歉,如果这是我应该能弄明白的事情。我做了很多研究,发现自己沉浸在(相关和无关的)信息中。我甚至不知道如何搜索我需要的信息

    我读过一些链接:


    对于我正在开发的应用程序,我必须做几乎相同的事情。我也很难找到关于它的信息。似乎我发现的一切都接近我所需要的,但并不是真正的解决方案。最后,我从一堆不同的博客帖子、文章等中收集了一些零碎的东西,然后把它们放在一起,让它发挥作用

    我记得你发布的两个链接“声明和基于令牌的身份验证”和“ASP.NET Web API 2在AngularJS应用程序中与Facebook和Google进行外部登录”都包含有用的信息

    我不能给你一个全面的答案,因为我不记得我必须做的每件事,甚至不知道我当时正在做的每件事,但我可以给你一个大概的想法。你在正确的轨道上

    基本上,我最终使用Facebook授予的令牌来确认他们登录了Facebook帐户,根据他们的Facebook用户ID创建了一个用户,并授予他们我自己的承载令牌,他们可以使用该令牌访问我的API

    流程如下所示:

  • 客户端通过任何方法(我们使用的)与Facebook进行身份验证
    • Facebook给他们一个代币
  • 客户端将令牌信息发送到我的WebApi控制器的注册端点
    • 该令牌使用Facebook的Graph API进行验证,该API返回用户信息
    • 用户通过ASP.NET身份在数据库中创建,其Facebook用户ID作为密钥
  • 客户端将令牌信息发送到我的WebApi控制器的身份验证端点
    • 该令牌使用Facebook的Graph API进行验证,该API返回用户信息
    • 用户信息用于在数据库中查找用户,确认他们以前已注册
    • ASP.NET标识用于为该用户生成新令牌
    • 该令牌将返回给客户端
  • 客户机在所有将来的HTTP请求中都包含一个授权头,其中包含我的服务授予的新令牌(例如“授权:承载令牌”)
    • 如果WebApi端点具有[Authorize]属性,则ASP.NET Identity将自动验证承载令牌,如果该令牌无效,则拒绝访问
  • 最终有很多自定义代码用于实现带有ASP.NET标识的OAuth,您包含的这些链接向您展示了其中的一些内容。希望这些信息能对您有所帮助,对不起,我帮不上更多的忙。

    我照做了。流程基本上是这样的

    • 服务器拥有facebook密钥,就像web登录一样
    • 该应用程序要求可用的社交登录并显示按钮(我想你可以硬编码)
    • 当按下按钮时,应用程序将打开浏览器并将URL设置为与指定社交登录相关的URL。然后,ASP.NET将浏览器重定向到facebook/google/任何带有相应挑战的位置
    • 用户可能已登录或未登录,也可能已授予您的应用权限。在他授予权限后,facebook将重定向回提供的回调URL
    • 此时,您可以从SignInManager获取外部登录信息,并检查该用户是否已存在以及是否应创建新帐户
    • 最后生成一个令牌,并将浏览器重定向到放置令牌的URL。应用程序从URL获取令牌并关闭浏览器。使用令牌继续处理API请求
    老实说,我不知道这种方法是否合法

    操作按钮的代码应重定向至:

    public async Task<IEnumerable<ExternalLoginDto>> GetExternalLogins(string returnUrl, bool generateState = false)
    {
        IEnumerable<AuthenticationScheme> loginProviders = await SignInManager.GetExternalAuthenticationSchemesAsync();
        var logins = new List<ExternalLoginDto>();
    
        string state;
    
        if (generateState)
        {
            const int strengthInBits = 256;
            state = RandomOAuthStateGenerator.Generate(strengthInBits);
        }
        else
        {
            state = null;
        }
    
        foreach (AuthenticationScheme authenticationScheme in loginProviders)
        {
            var routeValues = new
            {
                provider = authenticationScheme.Name,
                response_type = "token",
                client_id = Configuration["Jwt:Issuer"],
                redirect_uri = $"{Request.Scheme}//{Request.Host}{returnUrl}",
                state = state
            };
    
            var login = new ExternalLoginDto
            {
                Name = authenticationScheme.DisplayName,
                Url = Url.RouteUrl("ExternalLogin", routeValues),
                State = state
            };
    
            logins.Add(login);
        }
    
        return logins;
    }
    
    公共异步任务GetExternalLogins(字符串returnUrl,bool generateState=false) { IEnumerable loginProviders=Wait SignInManager.GetExternalAuthenticationSchemesAsync(); var logins=新列表(); 字符串状态; 如果(不动产) { 常数int-strengthInBits=256; state=RandomOAuthStateGenerator.Generate(strengthInBits); } 其他的 { state=null; } foreach(loginProviders中的AuthenticationScheme AuthenticationScheme) { var routeValues=新 { provider=authenticationScheme.Name,
    [Authorize(AuthenticationSchemes = "Identity.External")]
    [Route("ExternalLogin", Name = "ExternalLogin")]
    public async Task<IActionResult> GetExternalLogin(string provider, string state = null, string client_id = null, string error = null)
    {
        if (error != null)
        {
            ThrowBadRequest(error);
        }
    
        if (!User.Identity.IsAuthenticated)
        {
            return new ChallengeResult(provider);
        }
    
        string providerKey = User.FindFirstValue(ClaimTypes.NameIdentifier);
    
        var externalLoginInfo = new ExternalLoginInfo(User, User.Identity.AuthenticationType, providerKey, User.Identity.AuthenticationType);
    
        if (externalLoginInfo.LoginProvider != provider)
        {
            await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
            return new ChallengeResult(provider);
        }
    
        var userLoginInfo = new UserLoginInfo(externalLoginInfo.LoginProvider, externalLoginInfo.ProviderKey, externalLoginInfo.ProviderDisplayName);
        User user = await UserManager.FindByLoginAsync(externalLoginInfo.LoginProvider, externalLoginInfo.ProviderKey);
    
        if (client_id != Configuration["Jwt:Issuer"])
        {
            return Redirect($"/#error=invalid_client_id_{client_id}");
        }
    
        if (user != null)
        {
            return await LoginWithLocalUser(user, state);
        }
        else
        {
            string email = null;
            string firstName = null;
            string lastName = null;
    
            IEnumerable<Claim> claims = externalLoginInfo.Principal.Claims;
            if (externalLoginInfo.LoginProvider == "Google")
            {
                email = claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value;
                firstName = claims.FirstOrDefault(c => c.Type == ClaimTypes.GivenName)?.Value;
                lastName = claims.FirstOrDefault(c => c.Type == ClaimTypes.Surname)?.Value;
            }
            else if (externalLoginInfo.LoginProvider == "Facebook")
            {
                email = claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value;
    
                string[] nameParts = claims.First(c => c.Type == ClaimTypes.Name)?.Value.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                firstName = nameParts?.First();
                lastName = nameParts?.Last();
            }
    
            //some fallback just in case
            firstName ??= externalLoginInfo.Principal.Identity.Name;
            lastName ??= externalLoginInfo.Principal.Identity.Name;
    
            user = new User
            {
                UserName = email,
                Email = email,
                FirstName = firstName,
                LastName = lastName,
                EmailConfirmed = true //if the user logs in with Facebook consider the e-mail confirmed
            };
    
            IdentityResult userCreationResult = await UserManager.CreateAsync(user);
            if (userCreationResult.Succeeded)
            {
                userCreationResult = await UserManager.AddLoginAsync(user, userLoginInfo);
                if (userCreationResult.Succeeded)
                {
                    return await LoginWithLocalUser(user, state);
                }
            }
    
            string identityErrrors = String.Join(" ", userCreationResult.Errors.Select(ie => ie.Description));
            Logger.LogWarning($"Error registering user with external login. Email:{email}, Errors:" + Environment.NewLine + identityErrrors);
            return Redirect($"/#error={identityErrrors}");
        }
    }
    
    private async Task<RedirectResult> LoginWithLocalUser(User user, string state)
    {
        await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
    
        DateTime expirationDate = DateTime.UtcNow.AddDays(365);
    
        string token = user.GenerateJwtToken(Configuration["Jwt:Key"], Configuration["Jwt:Issuer"], expirationDate);
        return Redirect($"/#access_token={token}&token_type=bearer&expires_in={(int)(expirationDate - DateTime.UtcNow).TotalSeconds}&state={state}");
    }