2

I have a REST API built using ServiceStack. I am using BasicAuthentication without any issues when calling the REST APIs (I am registering the AuthFeature with the BasicAuthProvider).

Now I am trying to build some HTML management pages. These should also be authenticated.

The [Authenticate] attribute redirects to the /login page, so I created the following DTO and matching service to handle logins:

    [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; }
    }

However, the BasicAuthProvider always throws HttpError: "Invalid BasicAuth credentials" when I fill in username and password on the Login view page and POST these to the SiteLoginService. It is probably because the web browser is not filling in the Basic auth header, but I do not know how to authenticate with filled in username and password.

How to properly authenticate site users against the AuthProvider which works with the existing REST API?

4

2 回答 2

1

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

本文介绍了如何使用 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 发送用户名和密码,如果这是您想要的。如果您解释您的要求,我们可以给出一些建议。

于 2013-10-30T08:09:26.083 回答
1

我想我还需要在 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在 my 中调用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 属性填充到服务中。

于 2013-10-30T08:22:28.127 回答