【问题标题】:Authenticate users in Asp .net Web API在 Asp .net Web API 中对用户进行身份验证
【发布时间】:2018-06-30 19:12:56
【问题描述】:

我正在编写将被移动设备使用的 API,并且我想保护这个 API 端点。

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

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

【问题讨论】:

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


    【解决方案1】:

    这个问题有点宽泛;基本上,您正在寻找一种策略来使用不同的现有 API 对 Web api(dotnet 核心或普通框架?)的客户端进行身份验证和授权(该 API 在您的控制范围内,您可以根据需要对其进行修改吗?)

    如果您可以同时修改两者,请通过 StackOverflow 和 Google 查找 JWT 令牌、OAuth 和身份服务器。

    【讨论】:

    • 这两个项目都是用 .net 技术创建的。身份验证项目(我无法修改此项目)像普通身份框架操作方法一样公开端点,还有用于生成令牌的端点等。
    【解决方案2】:

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-13
      • 1970-01-01
      • 2013-11-14
      • 2013-11-16
      相关资源
      最近更新 更多