使用临时会话时工作正常。登录到auth服务并调用/ auth,不带任何参数,它显示显示名称,会话ID等。
当我使用RememberMe = true登录时,该调用会正确返回会话信息。但是在后续调用没有任何参数的/ auth时,ServiceStack会返回未经过身份验证的401。会话对象的IsAuthenticated属性为true且实际存在。我的代码检查了这一点,如果它是假的,则将用户转发到不会发生的登录页面,这样我就知道用户确实已经过身份验证。
我没有做任何不同的事情。如何通过永久会话进行身份验证并获得/ auth的后续调用以确认我已登录?
如果它有助于我使用CustomCredentialsProvider。
更新:
AppHost代码:
public override void Configure(Funq.Container container)
{
//Set JSON web services to return idiomatic JSON camelCase properties
ServiceStack.Text.JsConfig.EmitCamelCaseNames = true;
Config.RestrictAllCookiesToDomain = ConfigurationManager.AppSettings["cookieDomain"];
Plugins.Add(new AuthFeature(() => new CustomUserSession(),
new IAuthProvider[] {
new CustomCredentialsProvider()
{ SessionExpiry =
TimeSpan.FromMinutes(Convert.ToDouble(ConfigurationManager.AppSettings["SessionTimeout"]))
},
}) //end IAuthProvider
{
IncludeAssignRoleServices = false,
IncludeRegistrationService = false,
HtmlRedirect = ConfigurationManager.AppSettings["mainSiteLink"] + "Login.aspx"
} //end AuthFeature initializers
);//end plugins.add AuthFeature
Plugins.Add(new PostmanFeature() { EnableSessionExport = true });// this is only for when we want the feature and it's NOT in DebugMode
Plugins.Add(new SwaggerFeature());
Plugins.Add(new CorsFeature(allowedOrigins: "*",
allowedMethods: "GET, POST, PUT, DELETE, OPTIONS",
allowedHeaders: "Content-Type, Authorization, Accept",
allowCredentials: true));
container.Register<IRedisClientsManager>
(c => new PooledRedisClientManager(2, ConfigurationManager.AppSettings["redisIpPort"]));
container.Register<ICacheClient>(c => c.Resolve<IRedisClientsManager>().GetCacheClient());
container.Register<ISessionFactory>(c => new SessionFactory(c.Resolve<ICacheClient>()));
var userRep = new InMemoryAuthRepository();
container.Register<IUserAuthRepository>(userRep);
//Set MVC to use the same Funq IOC as ServiceStack
ControllerBuilder.Current.SetControllerFactory(new FunqControllerFactory(container));
#if DEBUG
Config.DebugMode = true;
typeof(Authenticate).AddAttributes
(
new RestrictAttribute
(RequestAttributes.HttpGet | RequestAttributes.HttpPost)
);
#else
typeof(Authenticate).AddAttributes(new RestrictAttribute(RequestAttributes.HttpPost));
#endif
RegisterTypedRequestFilter<Authenticate>((req, res, dto) =>
{
if (dto.UserName != null && dto.UserName != string.Empty
&& dto.Password != null && dto.Password != string.Empty)
if(dto.RememberMe == null)
dto.RememberMe = false;
});
RegisterTypedResponseFilter<AuthenticateResponse>((req, res, dto) =>
{
var appSettings = new ServiceStack.Configuration.AppSettings();
dto.UserId = AppHostBase.Instance.TryResolve<ICacheClient>().SessionAs<CustomUserSession>().UserId.ToString();
dto.Meta = new Dictionary<string, string>();
dto.Meta.Add("ExpiresMinutes", appSettings.Get("SessionTimeout"));
});
}
public static void Start()
{
Licensing.RegisterLicense(licenceKey);
new ServiceStackAppHost().Init();
}
初始请求标题:
的https://****.com/api2/auth用户名=用户安培;密码= passwordmberme =真
初始回复标题:
初步回复正文:
{&#34;用户id&#34;:&#34; 47&#34;&#34;的sessionId&#34;:&#34; PKrITmRawxAtnaABCDgN&#34;&#34;用户名&#34;:& #34;使用者&#34;&#34; responseStatus&#34;:{},&#34;元&#34; {&#34; ExpiresMinutes&#34;:&#34; 360&#34;}} < / p>
后续调用/ auth请求:
后续调用/ auth响应
后续调用/ auth正文:
{&#34; responseStatus&#34;:{&#34; errorCode&#34;:&#34;未经过身份验证&#34;,&#34;消息&#34;:&#34;未经过身份验证&#34 ;,&#34; stackTrace&#34;:&#34; [验证时间:2014年11月13日下午3:27:49]:\ n [请求:{}] \ n服务支持.HttpError:未经过身份验证\ r \ n at ServiceStack.Auth.AuthenticateService.Post(验证请求)\ r \ n在lambda_method(Closure,Object,Object)\ r \ n在ServiceStack.Host.ServiceRunner`1.Execute(IRequest请求,对象实例,TRequest requestDto)& #34;&#34;错误&#34;:[]}}
更新 我精心设计了一个小的Python3脚本来验证自己并调用其他一些Web服务。使用RememberMe = true进行身份验证后,cookie会按预期返回:ss-id / pid设置正常,ss-opt = perm。我想我会打印标题cookie并将其粘贴到另一个请求的标题中,以调用标记为[Authenticate]的其他服务。它没有用。所以我尝试了一些愚蠢的东西并将ss-pid cookie值粘贴到ss-id中。它奏效了。
这里是失败的cookie字符串(会话编辑:)):
cookie =&#34; ss-id = ss-ID-session-cookie ;域= .zola360.com;路径= /; HttpOnly, ss-pid = ss-PID-session-cookie ;域= .zola360.com; expires = Tue,14-Nov-2034 01:34:25 GMT;路径= /; HttpOnly,ss-opt = perm;域= .zola360.com; expires = Tue,14-Nov-2034 01:34:25 GMT;路径= /; HttpOnly,X-UAId =;域= .zola360.com; expires = Tue,14-Nov-2034 01:34:25 GMT;路径= /; HttpOnly,47 = 0;域= .zola360.com; path = /,UserId = 47;域= .zola360.com;路径= /&#34;
简单地将ss-pid值粘贴到ss-id中就可以了:
cookie =&#34; ss-id = ss-PID-session-cookie ;域= .zola360.com;路径= /; HttpOnly, ss-pid = ss-PID-session-cookie ;域= .zola360.com; expires = Tue,14-Nov-2034 01:34:25 GMT;路径= /; HttpOnly,ss-opt = perm;域= .zola360.com; expires = Tue,14-Nov-2034 01:34:25 GMT;路径= /; HttpOnly,X-UAId =;域= .zola360.com; expires = Tue,14-Nov-2034 01:34:25 GMT;路径= /; HttpOnly,47 = 0;域= .zola360.com; path = /,UserId = 47;域= .zola360.com;路径= /&#34;
我使用的Python3脚本:
import httplib2 as http
import json
try:
from urlparse import urlparse
except ImportError:
from urllib.parse import urlparse
headers = {
'Accept': 'application/json',
'Content-Type': 'application/json; charset=UTF-8'
}
uri = 'https://mysite.com'
path = '/api2/auth/credentials'
target = urlparse(uri+path)
method = 'POST'
body = '{"username": "username", "password": "password", "RememberMe": "true"}'.encode()
h = http.Http()
response, content = h.request(target.geturl(), method, body, headers)
#save the cookie and use it for subsequent requests
cookie = response['set-cookie']
print(cookie)
path2 = '/api2/time/start'
target2 = urlparse(uri+path2)
headers['cookie'] = cookie
response, content = h.request(target2.geturl(), 'GET', body, headers)
# assume that content is a json reply
# parse content with the json module
data = json.loads(content.decode())
print(data)
即使ss-opt = perm,似乎仍然会看到ss-id的值。
答案 0 :(得分:0)
使用GET /api2/auth?username=user&password=...
进行身份验证时,会使用您的永久Cookie ss-pid
进行身份验证,即:
Cookie: ss-pid=P2hslABCmSs7pomRqNz5; ss-opt=perm; X-UAId=
rememberme=true
选项告诉ServiceStack针对永久ss-pid
cookie维护用户会话。此选项在用户ss-opt=perm
cookie中维护,HTTP响应告诉客户端添加:
Set-Cookie: ss-opt=perm; domain=.zola360.com; expires=Mon, 13-Nov-2034 16:11:09 GMT; - path=/; HttpOnly
虽然在这种情况下不重要,但由于Request中缺少临时会话ss-id
,ServiceStack会告诉客户端添加一个新的:{/ p>
Set-Cookie: ss-id=pojZkNAdMcEcACDREcRM; domain=.zola360.com; path=/; HttpOnly
问题在于GET /api2/auth
的后续请求,其中客户端未重新发送最初通过身份验证的ss-pid
Cookie(即P2hslABCmSs7pomRqNz5
vs cvgslABCmSs6pomYdLu0
):
Cookie: ss-pid=cvgslABCmSs6pomYdLu0; ss-opt=perm; X-UAId=; ss-id=lYWZkFAdMcZcABCDcRM; 47=0; UserId=47
哪个ServiceStack不知道(即没有维护任何会话),这就是它按预期返回401 Not Authenticated
的原因。
目前尚不清楚您使用的HTTP客户端,但应将其配置为重新发送通常为默认行为的Cookie。 Ajax将仅为该浏览器会话发送永久ss-pid
个Cookie和临时ss-id
,例如当浏览器关闭时,临时ss-id
cookie将被丢弃,并且发出新请求将收到新的ss-id
cookie。
使用C# Service Clients,它只会重新发送永久性Cookie,因此客户端需要使用RememberMe = true
进行身份验证,例如:
var client = JsonServiceClient(BaseUrl);
var authResponse = client.Send(new Authenticate
{
provider = "credentials",
UserName = "user",
Password = "p@55word",
RememberMe = true,
});
authResponse.PrintDump();
经过身份验证后,可以使用相同的经过身份验证的client
实例多次访问受保护的记录as seen in this Auth Test:
for (int i = 0; i < 500; i++)
{
var response = client.Send<SecureResponse>(new Secured { Name = "test" });
Console.WriteLine("loop : {0}", i);
}