【问题标题】:How to use Basic authentication for web browser requests with ServiceStack?如何使用 ServiceStack 对 Web 浏览器请求使用基本身份验证?
【发布时间】:2013-11-09 00:02:47
【问题描述】:

我有一个使用 ServiceStack 构建的 REST API。我在调用 REST API 时使用 BasicAuthentication 没有任何问题(我正在使用 BasicAuthProvider 注册 AuthFeature)。

现在我正在尝试构建一些 HTML 管理页面。这些也应该经过身份验证。

[Authenticate] 属性重定向到 /login 页面,因此我创建了以下 DTO 和匹配服务来处理登录:

    [DefaultView("Login")]
    public class SiteLoginService : EnshareServiceBase
    {
        public object Get(SiteLoginRequest req)
        {
            return new SiteLoginRequest();
        }

        public object Post(SiteLoginRequest req)
        {
            //I am trying to use the registered IAuthProvider, which is the BasicAuthProvider
            var authProvider = ResolveService<IAuthProvider>();
            authProvider.Authenticate(this, EnshareSession,
                                      new ServiceStack.ServiceInterface.Auth.Auth()
                                      {
                                          Password = req.Password,
                                          UserName = req.UserName
                                      });
            return HttpResult.Redirect(req.Redirect);
        }
    }

    [Route("/login")]
    public class SiteLoginRequest : IReturn<SiteLoginRequest>
    {
        public string Redirect { get; set; }
        public string Password { get; set; }
        public string UserName { get; set; }
    }

但是,当我在登录视图页面上填写用户名和密码并将这些信息发布到 SiteLoginService 时,BasicAuthProvider 总是抛出 HttpError: "Invalid BasicAuth credentials"。可能是因为浏览器没有填写Basic auth header,但是我不知道如何通过填写的用户名和密码进行身份验证。

如何针对与现有 REST API 配合使用的 AuthProvider 正确验证站点用户身份?

【问题讨论】:

  • 您在注册AuthFeature时是否包含new BasicAuthProvider()
  • 最初我只包含了从 BasicAuthProvider 继承的 CustomAuthProvider。解决方案是还包括 CredentialsAuthProvider - 我在下面发布了自己的答案。

标签: authentication servicestack


【解决方案1】:

如果您将用户名和密码作为帖子传递,那么您怀疑您没有进行基本身份验证。

This article 解释了如何使用 JavaScript 进行基本身份验证。来自文章:

function login() {
    var username = document.getElementById(this.id + "-username").value;
    var password = document.getElementById(this.id + "-password").value;
    this.http.open("get", this.action, false, username, password);
    this.http.send("");
    if (http.status == 200) {
        document.location = this.action;
     } else {
        alert("Incorrect username and/or password.");
    }
    return false;
}

ServiceStack 还支持其他形式的身份验证,包括通过 POST 发送用户名和密码,如果这是您想要的。如果您解释您的要求,我们可以给出一些建议。

【讨论】:

  • 我不想使用 javascript 进行身份验证。我想从 html 表单做一个普通的 http 帖子。
【解决方案2】:

我想我还需要在 AuthFeature 中包含 CredentialsAuthProvider,这将公开 /auth/credentials 服务,我将表单发布到该服务。

        //this inherits the BasicAuthProvider and is used to authenticate the REST API calls
        var myCustomAuthProvider = new CustomAuthProvider(appSettings);
        var credentialsProvider = new CredentialsAuthProvider(appSettings);
        container.Register<IAuthProvider>(myCustomAuthProvider);
        container.Register<CredentialsAuthProvider>(credentialsProvider);
        var authFeature = new AuthFeature(() => new EnshareSession(new MongoTenantRepository()),
                                          new IAuthProvider[] {
                                                                  myCustomAuthProvider,
                                                                  credentialsProvider 
                                                               })

所以我在登录表单中将操作指定为 /auth/credentials,同时提供所需的用户名和密码字段。

        <form action="/auth/credentials" method="post">
            <p class="entryfield">
                @Html.LabelFor(m => m.UserName, "Login name:")
                @Html.TextBoxFor(u => u.UserName)
            </p>
            <p class="entryfield">
                @Html.LabelFor(m => m.Password)
                @Html.PasswordFor(m => m.Password)
            </p>
            <input class="formbutton" type="submit" value="Login" />
        </form>

当表单发布时,它会正确地命中身份验证代码流(TryAuthenticate 在我的 IUserAuthRepository 中被调用并返回 true)。

最终请求收到 302,我在 /login 的登录表单被重新显示。

    HTTP/1.1 302 Found
    Server: ASP.NET Development Server/10.0.0.0
    Date: Wed, 30 Oct 2013 08:15:54 GMT
    X-AspNet-Version: 4.0.30319
    X-Powered-By: ServiceStack/3,969 Win32NT/.NET
    Location: http://localhost:64944/login?redirect=%2fadmin
    Set-Cookie: X-UAId=3; expires=Sun, 30-Oct-2033 08:15:54 GMT; path=/; HttpOnly

它正在设置会话 cookie (X-AUId) 并且用户已正确验证。对使用 Authenticate 属性修饰的服务的后续 Web 浏览器请求成功。

所以唯一缺少的部分是如何确保用户在发布到/auth/credentials 后被正确重定向。

为确保重定向有效,快速浏览一下就会发现需要一个 Continue 参数。

所以这就是登录表单的外观(我为模型重用了 ServiceStack 中的 Auth 类):

    @inherits ViewPage<ServiceStack.ServiceInterface.Auth.Auth>
    @{

        Layout = "AdminLayout";
    }

    <form action="/auth/credentials" method="post">
        <p class="entryfield">
            @Html.LabelFor(m => m.UserName, "Login name:")
            @Html.TextBoxFor(u => u.UserName)
        </p>
        <p class="entryfield">
            @Html.LabelFor(m => m.Password)
            @Html.PasswordFor(m => m.Password)
        </p>
        @Html.HiddenFor(m => m.Continue)
        <input type="submit" value="Login" />
    </form>

Continue 属性从其模型的 Redirect 属性填充到服务中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-12
    • 2018-08-14
    • 2015-03-20
    • 1970-01-01
    • 1970-01-01
    • 2020-06-03
    相关资源
    最近更新 更多