3

我正在尝试设计我的第一个公共 API,并且我正在尝试了解 REST 如何与身份验证一起工作,尤其是在使用 js 框架(例如 angularJS)的完全客户端应用程序的上下文中。

假设您有一个客户端,它是一个浏览器应用程序(即,仅 HTML、JS、CSS)作为静态文件从 nginx 之类的东西使用 javascript 框架来使用 REST 服务,例如需要秘密访问密钥的东西为服务的每个请求创建一个签名,例如 Amazon S3。

在这个场景中的认证方面,如果你没有服务器端的应用程序,秘密访问密钥将如何处理,即你如何获得它,你将它存储在哪里等等?为每个请求提供密钥似乎是一种可怕的安全情况(即使它只发生一次以引导应用程序)。

即使你确实有一个轻量级的服务器端应用程序——你如何安全地通知客户端(它仍然调用经过身份验证的第 3 方 API 本身)它可能发出的每个请求的签名应该是什么?我对这应该如何从两端进行设计感到非常困惑。

4

1 回答 1

0

我已经完成了一些 AngularJS 应用程序,我发现的方法是使用HttpModule这样的一个:

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

namespace YourSolution.WebApp.Modules
{
    public class BasicAuthenticationHttpModule : IHttpModule
    {
        public BasicAuthenticationHttpModule()
        {
        }

        public void Init(HttpApplication context)
        {
            context.AuthenticateRequest += OnApplicationAuthenticateRequest;
            context.EndRequest += OnApplicationEndRequest;
        }

        private static void SetPrincipal(IPrincipal principal)
        {
            Thread.CurrentPrincipal = principal;
            if (HttpContext.Current != null)
            {
                HttpContext.Current.User = principal;
            }
        }

        private static bool CheckPassword(
            string username, string password)
        {
            return username == password;
        }

        private static void AuthenticateUser(string credentials)
        {
            try
            {
                var encoding = Encoding.GetEncoding(
                    "iso-8859-1");
                credentials = encoding.GetString(
                    Convert.FromBase64String(credentials));

                var separator = credentials.IndexOf(':');
                var name = credentials.Substring(0, separator);
                var password = credentials.Substring(separator + 1);

                var validated = CheckPassword(name, password);
                if (!validated) return;

                var identity = new GenericIdentity(name);
                SetPrincipal(new GenericPrincipal(identity, null));
            }
            catch (FormatException)
            {
            }
        }

        private static void OnApplicationAuthenticateRequest(
            object sender, EventArgs e)
        {
            var request = HttpContext.Current.Request;
            var authHeader = request.Headers["Authorization"];

            if (authHeader == null) return;

            var authHeaderVal = AuthenticationHeaderValue.Parse(authHeader);

            if (authHeaderVal.Scheme.Equals(
                "basic",
                StringComparison.OrdinalIgnoreCase)
                && authHeaderVal.Parameter != null)
            {
                AuthenticateUser(authHeaderVal.Parameter);
            }
        }

        private static void OnApplicationEndRequest(
            object sender, EventArgs e)
        {
            var response = HttpContext.Current.Response;
            if (response.StatusCode == 401)
            {
                //response.Headers.Add(
                //    "WWW-Authenticate",
                //    string.Format("Basic realm=\"{0}\"", Realm));
            }
        }

        public void Dispose()
        {
        }
    }
}

最重要的部分是内部CheckPassword方法,您应该在其中验证凭据。

另一点是这一行response.Headers.Add("WWW-Authenticate", string.Format("Basic realm=\"{0}\"", Realm));,如果你不评论这一行,经典的登录请求表单将出现,如果你评论这一行,你必须401在你的请求中捕获错误。

如果您想了解领域:基本身份验证中的“领域”是什么

另外,您需要在 web.config 文件中注册该模块:

<system.webServer>
    <modules>
        <add 
            name="BasicAuthenticationHttpModule"
            type="YourSolution.WebApp.Modules.BasicAuthenticationHttpModule" />
    </modules>
</system.webServer>

然后我添加了这两种方法来处理身份验证令牌:

// u: username; p: password
CreateBasicAuthenticationToken = function (u, p) {
    var t = u + ':' + p;
    var hat = btoa(t);
    window.sessionStorage.setItem('basicauthtoken', 'basic ' + hat);
};

DestroyBasicAuthenticationToken = function () {
    window.sessionStorage.removeItem('basicauthtoken');
};

btoa方法The btoa() method of window object is used to convert a given string to a encoded data (using base-64 encoding) string.:. 取自:http ://www.w3resource.com/javascript/client-object-property-method/window-btoa.php 。

最后,我使用以下命令将 authtoken 添加到请求标头中beforeSend

$.ajax({
    type: 'GET',
    url: 'your url',
    beforeSend: function (xhr) {
        window.sessionStorage.getItem('basicauthtoken');
    }
}).done(function (data, textStatus, xhr) {
    //...
});

注意,不建议在 Angular 指令之外使用 jQuery,AngularJS 最佳实践要求 jQuery 代码必须始终放在指令中。

希望能帮助到你。

于 2013-10-26T00:23:44.420 回答