How can I Authenticate with ServiceStack using jQu

2019-08-05 16:26发布

问题:

I'm trying to do something like the following: jQuery Part:

function ajaxLogin() {
    $.ajax({
         url: "auth/credentials",
         type: "POST",
         data: { UserName: $("#form_username").val(), Password: $("#form_pwd").val() },
         success: function (data) {
             $("#login_div").hide();
         },
         error: function (jqXHR,textStatus,errorThrown) {
             $("$login_msg").text(errorThrown);
         }
    });
}

However, for some reason it's always coming back to the success function and data contains the html contents of the current html document.

My ServiceStack AuthProvider contains the following TryAuthenticate:

public override bool TryAuthenticate(IServiceBase authService, string userName, string password)
    {
        var session = authService.GetSession();
        string error = null;
        try
        {
            var dataSource = authService.TryResolve<RiskViewDataSource>();
            var diModelInstance = dataSource.diModelRootObject;
            string authResult = UserFactory.authenticate(session.Id, userName, password, false);
            if ("OK".Equals(authResult))
            {
                session.IsAuthenticated = true;
                session.UserName = session.DisplayName = userName;
                session.UserAuthId = password;
                UsersManager.generateUsersPolicies();
                UsersManager.loadUserPolicies();
                return true;
            }
            else
            {
                session.IsAuthenticated = false;
                session.UserName = session.DisplayName = null;
                session.UserAuthId = null;
                authService.RemoveSession();
                return false;
            }
        }
        catch (Exception e)
        {
            Log.Error(e.ToString());
            session.IsAuthenticated = false;
            session.UserName = session.DisplayName = null;
            session.UserAuthId = null;
            error = "Could not connect to RiskView database";
        }

        if (error != null)
        {
            throw HttpError.Unauthorized(error);
        }
        else
        {
            return false;
        }
    }

回答1:

Ok, after a day of messing about I've come up with this solution which works for me. I had to create a new service request for logging in. I called it RenewSession.

Service Stack Part:

[Route("/RenewSession", "POST")]
public class RenewSessionRequest : IReturn<RenewSessionResponse>
{
}

public class RenewSessionResponse : IHasResponseStatus
{
    public RiskViewJsonObject Result { get; set; }
    public ResponseStatus ResponseStatus { get; set; }
}

public class RenewSessionService : Service, IPost<RenewSessionRequest>
{
    public object Post(RenewSessionRequest request)
    {
        string username = this.Request.GetParam("UserName");
        string password = this.Request.GetParam("Password");
        string message = "";

        IAuthProvider authService = AuthService.GetAuthProvider("credentials");
        Boolean success = false;
        try
        {
            var response = authService.Authenticate(this, this.GetSession(), new Auth { UserName = username, Continue = null, Password = password });
            success = true;
        }
        catch (Exception e)
        {
            message = e.ToResponseStatus().Message;
        }

        return new RenewSessionResponse { Result = new Mapping.RiskViewJsonObject("{ \"success\" : " + (success ? "true" : "false") + ", \"message\" : \"" + RiskViewJsonObject.cleanForJSON(message)+ "\" }") };
    }
}

Html and Ajax Part:

1) Add a div to the page for the login details (Hide it to start with)

<div id="login-div" style="position:absolute;display:hidden;left:100;top:100;background-image:url('images/login_bk.png');">
    <p id="login_error_msg"></p>
    <form id="login_form" onsubmit="loginSubmit(); return false;">
        <table>
            <tr>
                <td>Username:<input id="in_un" type="text" name="UserName" autocomplete="off" autocorrect="off" autocapitalize="off"/></td>
            </tr>
            <tr>
                <td>Password:<input id="in_pw" type="password" name="Password" autocomplete="off" autocorrect="off" autocapitalize="off"/></td>
            </tr>
            <tr>
                <td style="text-align: center;">
                    <input id="login_submit" type="submit" class="hand_cursor" value="Login">
                </td>
            </tr>
        </table>
    </form>
</div>

2) I add 401 checks to every ajax query on my page (401 tells us that the session has expired)

$.getJSON('/Menus?format=json', function(data) {
    // Do some stuff
}).fail(function (jqxhr,textStatus,error) {
    if (jqxhr.status == 401) {
        loginAgain();
    }
});

3) Show the div to re-login

function loginAgain(reloadMenu) {
    $("#login-div").show("slow");
}

4) The onclick for login button or onsubmit event for the login form

    function loginSubmit() {
        if ($("#in_un").val().trim() == "" || $("#in_pw").val().trim() == "") {
            $("#login_error_msg").text("Username or Password is still empty.");
            return false;   // Prevent form from submitting
        } else {
            $("#login_submit_btn").attr("disabled","disabled");
            $("#login_error_msg").text("");
            $.ajax({
                url: "/RenewSession?format=json",
                type: "POST",
                data: { UserName: $("#in_un").val(), Password: $("#in_pw").val() },
                success: function (data, textStatus, jqXHR) {
                    $("#login_submit_btn").removeAttr("disabled");
                    if (data.Result.success) {
                        $("#login-div").hide();
                    } else {
                        if (data.Result.message) {
                            $("#login_error_msg").text(data.Result.message);
                        } else {
                            $("#login_error_msg").text(textStatus);
                        }
                        $("#in_pw").focus();
                    }
                },
                error: function (jqXHR, textStatus, errorThrown) {
                    $("#login_submit_btn").removeAttr("disabled");
                    $("#login_error_msg").text("ERROR: "+errorThrown);
                    $("#in_pw").focus();
                }
            });
        }
        return false;   // Stop the form submiting, we're just gonna hide the div
    }