外部身份验证ASP.NET Web API

外部身份验证ASP.NET Web API,asp.net,asp.net-web-api2,Asp.net,Asp.net Web Api2,我有Web API和在不同的解决方案中调用Web API的客户端。我需要使用本地身份验证和现有用户数据对用户进行身份验证,还需要使用外部身份验证,如Google和Facebook 本地身份验证工作正常。但在验证外部登录时,我在调用api/Account/UserInfo时收到未经授权的响应。请注意,我能够从google帐户正确生成令牌 这是我的AccountController.cs文件 [Authorize] [RoutePrefix("api/Account")] [EnableCors("

我有Web API和在不同的解决方案中调用Web API的客户端。我需要使用本地身份验证和现有用户数据对用户进行身份验证,还需要使用外部身份验证,如Google和Facebook

本地身份验证工作正常。但在验证外部登录时,我在调用api/Account/UserInfo时收到未经授权的响应。请注意,我能够从google帐户正确生成令牌

这是我的AccountController.cs文件

[Authorize]
[RoutePrefix("api/Account")]
[EnableCors("*","*","*")]
public class AccountController : ApiController
{
    private const string LocalLoginProvider = "Local";
    private ApplicationUserManager _userManager;

    public AccountController()
    {
    }

    public AccountController(ApplicationUserManager userManager,
        ISecureDataFormat<AuthenticationTicket> accessTokenFormat)
    {
        UserManager = userManager;
        AccessTokenFormat = accessTokenFormat;
    }

    public ApplicationUserManager UserManager
    {
        get
        {
            return _userManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
        }
        private set
        {
            _userManager = value;
        }
    }

    public ISecureDataFormat<AuthenticationTicket> AccessTokenFormat { get; private set; }

    // GET api/Account/UserInfo
    [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
    //[AllowAnonymous]
    [Route("UserInfo")]
    public UserInfoViewModel GetUserInfo()
    {
        ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);

        return new UserInfoViewModel
        {
            Email = User.Identity.GetUserName(),
            HasRegistered = externalLogin == null,
            LoginProvider = externalLogin != null ? externalLogin.LoginProvider : null
        };
    }

    // POST api/Account/Logout
    [Route("Logout")]
    public IHttpActionResult Logout()
    {
        Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType);
        return Ok();
    }

    // GET api/Account/ManageInfo?returnUrl=%2F&generateState=true
    [Route("ManageInfo")]
    public async Task<ManageInfoViewModel> GetManageInfo(string returnUrl, bool generateState = false)
    {
        IdentityUser user = await UserManager.FindByIdAsync(User.Identity.GetUserId());

        if (user == null)
        {
            return null;
        }

        List<UserLoginInfoViewModel> logins = new List<UserLoginInfoViewModel>();

        foreach (IdentityUserLogin linkedAccount in user.Logins)
        {
            logins.Add(new UserLoginInfoViewModel
            {
                LoginProvider = linkedAccount.LoginProvider,
                ProviderKey = linkedAccount.ProviderKey
            });
        }

        if (user.PasswordHash != null)
        {
            logins.Add(new UserLoginInfoViewModel
            {
                LoginProvider = LocalLoginProvider,
                ProviderKey = user.UserName,
            });
        }

        return new ManageInfoViewModel
        {
            LocalLoginProvider = LocalLoginProvider,
            Email = user.UserName,
            Logins = logins,
            ExternalLoginProviders = GetExternalLogins(returnUrl, generateState)
        };
    }

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

        IdentityResult result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword,
            model.NewPassword);

        if (!result.Succeeded)
        {
            return GetErrorResult(result);
        }

        return Ok();
    }

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

        IdentityResult result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword);

        if (!result.Succeeded)
        {
            return GetErrorResult(result);
        }

        return Ok();
    }

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

        Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);

        AuthenticationTicket ticket = AccessTokenFormat.Unprotect(model.ExternalAccessToken);

        if (ticket == null || ticket.Identity == null || (ticket.Properties != null
            && ticket.Properties.ExpiresUtc.HasValue
            && ticket.Properties.ExpiresUtc.Value < DateTimeOffset.UtcNow))
        {
            return BadRequest("External login failure.");
        }

        ExternalLoginData externalData = ExternalLoginData.FromIdentity(ticket.Identity);

        if (externalData == null)
        {
            return BadRequest("The external login is already associated with an account.");
        }

        IdentityResult result = await UserManager.AddLoginAsync(User.Identity.GetUserId(),
            new UserLoginInfo(externalData.LoginProvider, externalData.ProviderKey));

        if (!result.Succeeded)
        {
            return GetErrorResult(result);
        }

        return Ok();
    }

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

        IdentityResult result;

        if (model.LoginProvider == LocalLoginProvider)
        {
            result = await UserManager.RemovePasswordAsync(User.Identity.GetUserId());
        }
        else
        {
            result = await UserManager.RemoveLoginAsync(User.Identity.GetUserId(),
                new UserLoginInfo(model.LoginProvider, model.ProviderKey));
        }

        if (!result.Succeeded)
        {
            return GetErrorResult(result);
        }

        return Ok();
    }

    // GET api/Account/ExternalLogin
    [OverrideAuthentication]
    [HostAuthentication(DefaultAuthenticationTypes.ExternalCookie)]
    [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
    [AllowAnonymous]
    [Route("ExternalLogin", Name = "ExternalLogin")]
    public async Task<IHttpActionResult> GetExternalLogin(string provider, string error = null)
    {
        if (error != null)
        {
            return Redirect(Url.Content("~/") + "#error=" + Uri.EscapeDataString(error));
        }

        if (!User.Identity.IsAuthenticated)
        {
            return new ChallengeResult(provider, this);
        }

        ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);

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

        if (externalLogin.LoginProvider != provider)
        {
            Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
            return new ChallengeResult(provider, this);
        }

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

        bool hasRegistered = user != null;

        if (hasRegistered)
        {
            Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);

            ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(UserManager,
               OAuthDefaults.AuthenticationType);
            ClaimsIdentity cookieIdentity = await user.GenerateUserIdentityAsync(UserManager,
                CookieAuthenticationDefaults.AuthenticationType);

            AuthenticationProperties properties = ApplicationOAuthProvider.CreateProperties(user.UserName);
            Authentication.SignIn(properties, oAuthIdentity, cookieIdentity);
        }
        else
        {
            IEnumerable<Claim> claims = externalLogin.GetClaims();
            ClaimsIdentity identity = new ClaimsIdentity(claims, OAuthDefaults.AuthenticationType);
            Authentication.SignIn(identity);
        }

        return Ok();
    }

    // GET api/Account/ExternalLogins?returnUrl=%2F&generateState=true
    [AllowAnonymous]
    [Route("ExternalLogins")]
    public IEnumerable<ExternalLoginViewModel> GetExternalLogins(string returnUrl, bool generateState = false)
    {
        IEnumerable<AuthenticationDescription> descriptions = Authentication.GetExternalAuthenticationTypes();
        List<ExternalLoginViewModel> logins = new List<ExternalLoginViewModel>();

        string state;

        if (generateState)
        {
            const int strengthInBits = 256;
            state = RandomOAuthStateGenerator.Generate(strengthInBits);
        }
        else
        {
            state = null;
        }

        foreach (AuthenticationDescription description in descriptions)
        {
            ExternalLoginViewModel login = new ExternalLoginViewModel
            {
                Name = description.Caption,
                Url = Url.Route("ExternalLogin", new
                {
                    provider = description.AuthenticationType,
                    response_type = "token",
                    client_id = Startup.PublicClientId,
                    redirect_uri = new Uri(Request.RequestUri, returnUrl).AbsoluteUri,
                    state = state
                }),
                State = state
            };
            logins.Add(login);
        }

        return logins;
    }

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

        var user = new ApplicationUser()
        {
            UserName = model.Email,
            Email = model.Email,
            FirstName = model.FirstName,
            LastName = model.LastName,
            CellNumber = model.CellNumber,
            CompanyName = model.CompanyName,
            Address = model.Address,
            City = model.City,
            Country = model.Country,
            State = model.State,
            Zip = model.Zip,
            EmailConfirmed = true
        };

        IdentityResult result = await UserManager.CreateAsync(user, model.Password);

        if (!result.Succeeded)
        {
            return GetErrorResult(result);
        }

        return Ok("User Registered Successfully!");
    }

    // POST api/Account/RegisterExternal
    [OverrideAuthentication]
    //[AllowAnonymous]
    [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
    [Route("RegisterExternal")]
    public async Task<IHttpActionResult> RegisterExternal()
    {
        var info = await Authentication.GetExternalLoginInfoAsync();
        if (info == null)
        {
            return InternalServerError();
        }

        var user = new ApplicationUser() { UserName = info.Email, Email = info.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();
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing && _userManager != null)
        {
            _userManager.Dispose();
            _userManager = null;
        }

        base.Dispose(disposing);
    }

    #region Helpers

    private IAuthenticationManager Authentication
    {
        get { return Request.GetOwinContext().Authentication; }
    }

    private IHttpActionResult GetErrorResult(IdentityResult result)
    {
        if (result == null)
        {
            return InternalServerError();
        }

        if (!result.Succeeded)
        {
            if (result.Errors != null)
            {
                foreach (string error in result.Errors)
                {
                    ModelState.AddModelError("", error);
                }
            }

            if (ModelState.IsValid)
            {
                // No ModelState errors are available to send, so just return an empty BadRequest.
                return BadRequest();
            }

            return BadRequest(ModelState);
        }

        return null;
    }

    private class ExternalLoginData
    {
        public string LoginProvider { get; set; }
        public string ProviderKey { get; set; }
        public string UserName { get; set; }

        public IList<Claim> GetClaims()
        {
            IList<Claim> claims = new List<Claim>();
            claims.Add(new Claim(ClaimTypes.NameIdentifier, ProviderKey, null, LoginProvider));

            if (UserName != null)
            {
                claims.Add(new Claim(ClaimTypes.Name, UserName, null, LoginProvider));
            }

            return claims;
        }

        public static ExternalLoginData FromIdentity(ClaimsIdentity identity)
        {
            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)
            };
        }
    }

    private static class RandomOAuthStateGenerator
    {
        private static RandomNumberGenerator _random = new RNGCryptoServiceProvider();

        public static string Generate(int strengthInBits)
        {
            const int bitsPerByte = 8;

            if (strengthInBits % bitsPerByte != 0)
            {
                throw new ArgumentException("strengthInBits must be evenly divisible by 8.", "strengthInBits");
            }

            int strengthInBytes = strengthInBits / bitsPerByte;

            byte[] data = new byte[strengthInBytes];
            _random.GetBytes(data);
            return HttpServerUtility.UrlTokenEncode(data);
        }
    }

    #endregion
}
}

}


}这是我用来获取信息的代码。它的工作很好:

        // check if authorized
        if (Request["code"] == null)
        {
            Response.Redirect(string.Format(
                "https://graph.facebook.com/oauth/authorize?client_id={0}&redirect_uri={1}&scope={2}",
                app_id, Request.Url.AbsoluteUri, scope));
        }
        else
        {
            FacebookAccessToken token = new FacebookAccessToken();
            FacebookUser user = new FacebookUser();

            //Requesting for access token
            string url = string.Format("https://graph.facebook.com/oauth/access_token?client_id={0}&redirect_uri={1}&scope={2}&code={3}&client_secret={4}",
                app_id, Request.Url.AbsoluteUri, scope, Request["code"].ToString(), app_secret);

            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;

            using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
            {
                StreamReader reader = new StreamReader(response.GetResponseStream());

                string vals = reader.ReadToEnd();
                // Deserialize json object
                token = JsonConvert.DeserializeObject<FacebookAccessToken>(data);
            }

            //Getting user info
            url = string.Format("https://graph.facebook.com/v2.8/me?access_token={0}", token.AccessToken);
            request = WebRequest.Create(url) as HttpWebRequest;
            using (var client = request.GetResponse() as HttpWebResponse)
            {
                StreamReader reader = new StreamReader(client.GetResponseStream());
                string data = reader.ReadToEnd();
                // data:"{\"name\":\"Er Vatsal D Patel\",\"id\":\"13168723650*****\"}";
                user = JsonConvert.DeserializeObject<FacebookUser>(data);

            }

        return "done";
    }
//检查是否已授权
如果(请求[“代码”]==null)
{
重定向(string.Format(
"https://graph.facebook.com/oauth/authorize?client_id={0}&redirect_uri={1}&scope={2}“,
app_id,Request.Url.AbsoluteUri,scope));
}
其他的
{
FacebookAccessToken令牌=新的FacebookAccessToken();
FacebookUser=新的FacebookUser();
//请求访问令牌
字符串url=string.Format(“https://graph.facebook.com/oauth/access_token?client_id={0}&redirect_uri={1}&scope={2}&code={3}&client_secret={4}”,
app_id,Request.Url.AbsoluteUri,作用域,Request[“code”]。ToString(),app_secret);
HttpWebRequest-request=WebRequest.Create(url)为HttpWebRequest;
使用(HttpWebResponse=request.GetResponse()作为HttpWebResponse)
{
StreamReader=新的StreamReader(response.GetResponseStream());
字符串vals=reader.ReadToEnd();
//反序列化json对象
token=JsonConvert.DeserializeObject(数据);
}
//获取用户信息
url=string.Format(“https://graph.facebook.com/v2.8/me?access_token={0}”,token.AccessToken);
request=WebRequest.Create(url)为HttpWebRequest;
使用(var client=request.GetResponse()作为HttpWebResponse)
{
StreamReader=新的StreamReader(client.GetResponseStream());
字符串数据=reader.ReadToEnd();
//数据:“{\'name\':\'Er Vatsal D Patel\',\'id\':\'13168723650*****\”;
user=JsonConvert.DeserializeObject(数据);
}
返回“完成”;
}

再次感谢您,我需要google和face book登录以及本地web api登录。如果调用任何控制器中的任何方法,我还需要知道哪个用户登录。您已共享的Facebook实现很好。你能帮我做一下谷歌和本地认证吗?当我通过网络从远程机器访问托管API时,得到的答复是:无效的授权类型。请帮忙!如果有,请通过github共享您的代码。如前所述,无论您是否传递有效的授权类型,我都为web api和调用apiCheck的客户端提供了单独的解决方案。对于使用google的外部身份验证,请选择以下链接:
    function getAccessToken() {
if (location.hash) {
    if (location.hash.split('access_token=')) {
        var accessToken = location.hash.split('access_token=')[1].split('&')[0];
        if (accessToken) {
            isUserRegistered(accessToken);
        }
    }
}
     function isUserRegistered(accessToken) {
$.ajax({
    url: 'http://localhostXXXX/api/Account/UserInfo',
    method: 'GET',
    cors: 
        {
            headers: {
                'content-type': 'application/JSON',
                'Authorization': 'Bearer ' + accessToken
            }
        },
    success: function (response) {
        if (response.HasRegistered) {
            localStorage.setItem('accessToken', accessToken);
            localStorage.setItem('userName', response.Email);
            window.location.href = "Data.aspx";
        }
        else {
            signupExternalUser(accessToken);
        }
    }
});
     function signupExternalUser(accessToken) {
$.ajax({
    url: 'http://localhost:XXXXX/api/Account/RegisterExternal',
    method: 'POST',
    cors: 
      {
          headers: {
              'content-type': 'application/json',
              'Authorization': 'Bearer ' + accessToken
          }
      },
    success: function () {
        window.location.href = "";
    }
});
        // check if authorized
        if (Request["code"] == null)
        {
            Response.Redirect(string.Format(
                "https://graph.facebook.com/oauth/authorize?client_id={0}&redirect_uri={1}&scope={2}",
                app_id, Request.Url.AbsoluteUri, scope));
        }
        else
        {
            FacebookAccessToken token = new FacebookAccessToken();
            FacebookUser user = new FacebookUser();

            //Requesting for access token
            string url = string.Format("https://graph.facebook.com/oauth/access_token?client_id={0}&redirect_uri={1}&scope={2}&code={3}&client_secret={4}",
                app_id, Request.Url.AbsoluteUri, scope, Request["code"].ToString(), app_secret);

            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;

            using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
            {
                StreamReader reader = new StreamReader(response.GetResponseStream());

                string vals = reader.ReadToEnd();
                // Deserialize json object
                token = JsonConvert.DeserializeObject<FacebookAccessToken>(data);
            }

            //Getting user info
            url = string.Format("https://graph.facebook.com/v2.8/me?access_token={0}", token.AccessToken);
            request = WebRequest.Create(url) as HttpWebRequest;
            using (var client = request.GetResponse() as HttpWebResponse)
            {
                StreamReader reader = new StreamReader(client.GetResponseStream());
                string data = reader.ReadToEnd();
                // data:"{\"name\":\"Er Vatsal D Patel\",\"id\":\"13168723650*****\"}";
                user = JsonConvert.DeserializeObject<FacebookUser>(data);

            }

        return "done";
    }