在客户端标头或Cookie中使用sessionId时找不到ServiceStack用户会话

时间:2015-02-10 03:07:44

标签: client servicestack session-cookies

我正在使用带有自定义身份验证的ServiceStack v4。这是设置和正常工作。我可以调用/ auth服务并获得具有唯一SessionId的返回AuthorizationResponse。

我也有swagger-ui插件设置。使用它,我可以通过/ auth进行身份验证,然后调用我需要身份验证的其他服务之一。

现在,从使用c#JsonServiceClient的辅助MVC应用程序,我可以再次成功调用/ auth,然后使用相同的客户端对象保护服务。但是,如果我处置该客户端(在将唯一的sessionId保存到cookie之后),则稍后创建一个新客户端,并将sessionId添加为Cookie或使用x-ss-pid添加标头,如调用服务返回401.如果我调用非安全服务,但随后尝试访问唯一用户会话,则返回新会话。

如果我查看该服务中的请求标头,则使用sessionId明确设置cookie或标头。 sessionId也存在于sessionCache中。问题似乎是试图从请求中获取会话的代码没有找到它。

更具体地说,似乎ServiceExtensions.GetSessionId正在查看HostContext而不是调用Request。我不确定为什么。也许我在这里误解了一些东西。

如果我直接尝试使用以下代码获取我预期的会话,则会发现它没有问题。

  var req = base.Request;
  var sessionId = req.GetHeader("X-" + SessionFeature.PermanentSessionId);

  var sessionKey = SessionFeature.GetSessionKey(sessionId);
  var session = (sessionKey != null ? Cache.Get<IAuthSession>(sessionKey) : null)?? SessionFeature.CreateNewSession(req, sessionId);

那么,我错过了一些明显的东西吗?或者在创建我的辅助客户端时可能不那么明显?

客户来电的示例代码

这是我的授权码。它包含在Controller类中。这只是相关部分。

using (var client = new JsonServiceClient(WebHelper.BuildApiUrl(Request)))
{
    try
    {
        loginResult = client.Post(new Authenticate()
                       {
                           UserName = model.Email,
                           Password = model.Password,
                           RememberMe = model.RememberMe
                       });

        Response.SetCookie(new HttpCookie(SessionFeature.PermanentSessionId, loginResult.SessionId));

        return true;
     }
}

这是我的辅助客户端设置和服务调用,包含在MVC应用程序的另一个区域中的自己的控制器类

using (var client = new JsonServiceClient(WebHelper.BuildApiUrl(Request)))
{
    var cCookie = HttpContext.Request.Cookies.Get(SessionFeature.PermanentSessionId);
    if (cCookie != null)
    {
        client.Headers.Add("X-" + SessionFeature.PermanentSessionId, cCookie.Value);
        client.Headers.Add("X-" + SessionFeature.SessionOptionsKey, "perm");

    }

    response = client.Get(new SubscriptionStatusRequest());
}

其他更新

在Authenticate过程中,从HttpRequestExtensions调用以下函数,名称为= SessionFeature.PermanentSessionId

public static class HttpRequestExtensions
{
    /// <summary>
    /// Gets string value from Items[name] then Cookies[name] if exists.
    /// Useful when *first* setting the users response cookie in the request filter.
    /// To access the value for this initial request you need to set it in Items[].
    /// </summary>
    /// <returns>string value or null if it doesn't exist</returns>
    public static string GetItemOrCookie(this IRequest httpReq, string name)
    {
        object value;
        if (httpReq.Items.TryGetValue(name, out value)) return value.ToString();

        Cookie cookie;
        if (httpReq.Cookies.TryGetValue(name, out cookie)) return cookie.Value;

        return null;
    }

现在发生的是httpReq.Items包含一个SessionFeature.PermanentSessionId值,但我不知道为什么以及在哪里设置它。此时我甚至不理解Items容器在IRequest上的含义。因此,代码永远不会获得检查我的cookie或标题的功能

2 个答案:

答案 0 :(得分:2)

Session wiki描述了ServiceStack Session使用的不同cookie。

如果客户端想要使用永久SessionId(即ss-pid),它还需要发送ss-opt=perm Cookie以表明它想要使用永久会话。在身份验证期间使用RememberMe=true选项进行身份验证时,会自动设置此Cookie。

Session RequestFilter中存在一个问题,用于确保会话ID附加到当前请求时未使用公共IRequest.GetPermanentSessionId() API,它也在HTTP标头中查找SessionIds。这已解决with this commit,现在可以使用HTTP标头创建会话请求,例如:

//First Authenticate to setup an Authenticated Session with the Server
var client = new JsonServiceClient(BaseUrl);
var authResponse = client.Send(new Authenticate
{
    provider = CredentialsAuthProvider.Name,
    UserName = "user",
    Password = "p@55word",
    RememberMe = true,
});

//Use new Client instance without Session Cookies populated 
var clientWithHeaders = new JsonServiceClient(BaseUrl);
clientWithHeaders.Headers["X-ss-pid"] = authResponse.SessionId;
clientWithHeaders.Headers["X-ss-opt"] = "perm";

var response = clientWithHeaders.Send(new AuthOnly()); //success

此修补程序可从 v4.0.37 + 获得,现在为available on MyGet

答案 1 :(得分:1)

但是,如果我处置该客户端(将唯一的sessionId保存到cookie后)

如果客户端被放置在哪里,您要保存sessionId的cookie?此answer可能会提供一些其他信息。

然后创建一个新客户端,并将sessionId添加为Cookie或使用x-ss-pid通过标头添加文档,调用服务返回401

如果您将有效的sessionId存储/保存为字符串,您应该能够在新客户端的CookieContainer中提供它(假设sessionId仍然经过身份验证)。我知道你说过你尝试将sessionId添加为Cookie但是我没有使用CookieContainer在你的问题中看到示例所以它应该看起来像......

using (var client = new JsonServiceClient(WebHelper.BuildApiUrl(Request)))
{
    var cCookieId = savedCookieId; //a string that I believe you saved from a successfully authenticated client that is now disposed
    if (cCookieId != null)
    {
        var cookie = new Cookie(SessionFeature.PermanentSessionId, cCookieId);
        //cookie.Domian = "somedomain.com" //you will probably need to supply this as well
        client.CookieContainer.Add(cookie)
    }

    response = client.Get(new SubscriptionStatusRequest());
}