在Asp .net Web API中验证用户

时间:2018-01-22 07:47:14

标签: c# asp.net asp.net-web-api asp.net-identity identity

我正在编写将由移动设备使用的API,并且我希望保护此API端点。

用户身份验证详细信息由另一个名为User Manger API的应用程序提供(另一个包含用户详细信息的项目)。

如何利用ASP.NET Identity框架授权和其他功能来保护我的API端点,同时从用户管理器API获取用户数据?

2 个答案:

答案 0 :(得分:1)

问题有点宽泛;基本上你是在寻找一种策略,使用不同的现有API对web api(dotnet核心或普通框架?)的客户端进行身份验证和授权(在你的控件中是API,你可以根据需要进行修改吗?)

如果您可以同时修改这两项内容,则可以通过StackOverflow和Google查看JWT令牌,OAuth和身份服务器。

答案 1 :(得分:1)

1-你可以实现一个属性并装饰你的api控制器。

2-您可以在asp.net的app_start中实现并注册全局过滤器(并确保在global.asax中注册过滤器)。

3-你可以做什么#Roel-Abspoel提到在你的用户管理器API中实现Identity Server并让你的客户端与它通信并获取令牌,然后你的API与它通话来验证令牌。

还有其他方法,但我会保持这简短和甜蜜。

以下是使用属性的示例:

using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Filters;

namespace myExample
{
    public class ExternalAuthenticationAttribute : IAuthenticationFilter
    {
        public virtual bool AllowMultiple
        {
            get { return false; }
        }

        public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
        {
            // get request + authorization headers
            HttpRequestMessage request = context.Request;
            AuthenticationHeaderValue authorization = request.Headers.Authorization;

            // check for username and password (regardless if it was validated on the client, server should check)
            // this will only accept Basic Authorization
            if (String.IsNullOrEmpty(authorization.Parameter) || authorization.Scheme != "Basic")
            {
                // Authentication was attempted but failed. Set ErrorResult to indicate an error.
                context.ErrorResult = new AuthenticationFailureResult("Missing credentials", request);
                return null;
            }
            var userNameAndPasword = GetCredentials(authorization.Parameter);
            if (userNameAndPasword == null)
            {
                // Authentication was attempted but failed. Set ErrorResult to indicate an error.
                context.ErrorResult = new AuthenticationFailureResult("Could not get credentials", request);
                return null;
            }

            // now that we have the username + password call User manager API
            var client = new HttpClient();
            // POST USERNAME + PASSWORD INSIDE BODY, not header, not query string. ALSO USE HTTPS to make sure it is sent encrypted
            var response = AuthenticateAgainstUserMapagerApi1(userNameAndPasword, client);

            // THIS WILL WORK IN .NET CORE 1.1. ALSO USE HTTPS to make sure it is sent encrypted
            //var response = AuthenticateAgainstUserMapagerApi2(client, userNameAndPasword);

            // parse response
            if (!response.IsSuccessStatusCode)
            {
                context.ErrorResult = new AuthenticationFailureResult("Invalid username or password", request);
            }
            else
            {
                var readTask = response.Content.ReadAsStringAsync();
                var content = readTask.Result;
                context.Principal = GetPrincipal(content); // if User manager API returns a user principal as JSON we would 
            }

            return null;
        }

        //private static HttpResponseMessage AuthenticateAgainstUserMapagerApi2(HttpClient client, Tuple<string, string> userNameAndPasword)
        //{
        //    client.SetBasicAuthentication(userNameAndPasword.Item1, userNameAndPasword.Item2);
        //    var responseTask = client.GetAsync("https://your_user_manager_api_URL/api/authenticate");
        //    return responseTask.Result;
        //}

        private static HttpResponseMessage AuthenticateAgainstUserMapagerApi1(Tuple<string, string> userNameAndPasword, HttpClient client)
        {
            var credentials = new
            {
                Username = userNameAndPasword.Item1,
                Password = userNameAndPasword.Item2
            };
            var responseTask = client.PostAsJsonAsync("https://your_user_manager_api_URL/api/authenticate", credentials);
            var response = responseTask.Result;
            return response;
        }

        public IPrincipal GetPrincipal(string principalStr)
        {
            // deserialize principalStr and return a proper Principal instead of ClaimsPrincipal below
            return new ClaimsPrincipal();
        }

        private static Tuple<string, string> GetCredentials(string authorizationParameter)
        {
            byte[] credentialBytes;

            try
            {
                credentialBytes = Convert.FromBase64String(authorizationParameter);
            }
            catch (FormatException)
            {
                return null;
            }

            try
            {
                // make sure you use the proper encoding which match client
                var encoding = Encoding.ASCII;
                string decodedCredentials;
                decodedCredentials = encoding.GetString(credentialBytes);
                int colonIndex = decodedCredentials.IndexOf(':');
                string userName = decodedCredentials.Substring(0, colonIndex);
                string password = decodedCredentials.Substring(colonIndex + 1);
                return new Tuple<string, string>(userName, password);
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }
    }

    public class AuthenticationFailureResult : IHttpActionResult
    {
        public AuthenticationFailureResult(string reasonPhrase, HttpRequestMessage request)
        {
            ReasonPhrase = reasonPhrase;
            Request = request;
        }

        public string ReasonPhrase { get; private set; }

        public HttpRequestMessage Request { get; private set; }

        public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
        {
            return Task.FromResult(Execute());
        }

        private HttpResponseMessage Execute()
        {
            HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
            response.RequestMessage = Request;
            response.ReasonPhrase = ReasonPhrase;
            return response;
        }
    }
}

使用您的API类上的属性,每次访问PurchaseController时都会调用User Manager API:

[ExternalAuthenticationAttribute]
public class PurchaseController : ApiController