Проверка подлинности службы аутентификации не выполняется при использовании постоянных сеансов
При использовании временных сессий работает нормально. Войдите в службу аутентификации и вызов / аутентификация без каких-либо параметров, и это показывает отображаемое имя, идентификатор сессии и т. Д.
Когда я вхожу с 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= истина
- GET /api2/auth? Username=user&password=password& запомнить me=true HTTP/1.1
- Принять: текст / html, приложение / xhtml + xml, /
- Accept-Language: en-US
- Пользователь-агент: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0), как Gecko
- Accept-Encoding: gzip, выкачать
- Ведущий: propel.zola360.com
- DNT: 1
- Подключение: Keep-Alive
- Cookie: ss-pid = P2hslABCmSs7pomRqNz5; сс-OPT = завивка; X-UAId =
Заголовки начального ответа:
- HTTP / 1.1 200 ОК
- Cache-Control: приватный
- Тип контента: текст / HTML
- Контент-кодировка: gzip
- Варьируется: Accept-Encoding
- Сервер: Microsoft-IIS / 7.5
- X-Powered-By: ServiceStack / 4.033 Win32NT /.NET
- Access-Control-Allow-Origin: *
- Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
- Access-Control-Allow-Headers: Content-Type, Authorization, Accept
- Access-Control-Allow-Credentials: правда
- X-AspNet-версия: 4.0.30319
- Set-Cookie: ss-id = pojZkNAdMcEcACDREcRM; домен =.zola360.com; Путь = /; HttpOnly
- Set-Cookie: ss-opt = perm; домен =.zola360.com; истекает = понедельник, 13 ноября 2034 16:11:09 GMT; - путь = /; HttpOnly
- Set-Cookie: X-UAId =; домен =.zola360.com; истекает = понедельник, 13 ноября 2034 16:11:09 GMT; Путь = /; HttpOnly
- Set-Cookie: 47 = 0; домен =.zola360.com; Путь = /
- Set-Cookie: UserId = 47; домен =.zola360.com; Путь = /
- X-Powered-By: ASP.NET
- Дата: чт, 13 ноября 2014 16:11:09 GMT
- Длина контента: 4129
Начальный ответ тела:
{ "Идентификатор пользователя":"47","SESSIONID":"PKrITmRawxAtnaABCDgN","имя_пользователя": "пользователь","responseStatus":{},"мета":{"ExpiresMinutes":"360"}}
Последующий вызов / запрос авторизации:
- GET / api2 / auth HTTP / 1.1
- Принять: текст / html, приложение / xhtml + xml, /
- Accept-Language: en-US
- Пользователь-агент: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0), как Gecko
- Accept-Encoding: gzip, выкачать
- Ведущий: propel.zola360.com
- DNT: 1
- Подключение: Keep-Alive
- Cookie: ss-pid = cvgslABCmSs6pomYdLu0; сс-OPT = завивка; X-UAId=; сс-ID =lYWZkFAdMcZcABCDcRM; 47=0; UserId=47
Последующий вызов к / auth response
- HTTP / 1.1 401 не аутентифицирован
- Cache-Control: приватный
- Тип контента: текст / HTML
- Варь: Принять
- Сервер: Microsoft-IIS / 7.5
- X-Powered-By: ServiceStack / 4.033 Win32NT /.NET
- Access-Control-Allow-Origin: *
- Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
- Access-Control-Allow-Headers: Content-Type, Authorization, Accept
- Access-Control-Allow-Credentials: правда
- X-AspNet-версия: 4.0.30319
- X-Powered-By: ASP.NET
- Дата: четверг, 13 ноября 2014 г. 16:11:23 GMT
- Длина контента: 9731
Последующий звонок в / auth body:
{"responseStatus": {"errorCode": "Not Authenticated", "message": "Not Authenticated", "stackTrace": "[Authenticate: 13.11.2014 15:27:49 PM]:\n[ЗАПРОС: {}]\nServiceStack.HttpError: Не аутентифицировано \r\n в ServiceStack.Auth.AuthenticateService.Post(запрос аутентификации)\r\n в lambda_method(Closure, Object, Object)\r\n в ServiceStack.Host.ServiceRunner`1.Execute(запрос IRequest, экземпляр объекта, запрос TRequestDto)","errors":[]}}
Обновление Я создал небольшой скрипт на Python3 для аутентификации и вызова другого веб-сервиса. После аутентификации с использованием RememberMe = true файлы cookie возвращаются, как и ожидалось: ss-id / pid установлены нормально и ss-opt = perm. Я решил напечатать cookie заголовка и просто вставить его в заголовок другого запроса, чтобы вызвать другой сервис, помеченный [Authenticate]. Это не сработало. Поэтому я попробовал что-то глупое и вставил значение cookie ss-pid в значение ss-id. Это сработало.
Вот ошибочная строка cookie (сессия отредактирована:)):
cookie = "ss-id = ss-ID-session-cookie; домен =.zola360.com; путь = /; HttpOnly, ss-pid = ss-PID-сеанс-cookie; домен =.zola360.com; истекает = вт, 14 ноября 2034 01:34:25 GMT; путь =/; HttpOnly, ss-opt=perm; домен =.zola360.com; срок действия = вт, 14 ноября 2034 01:34:25 GMT; путь =/; HttpOnly, X-UAId=; домен =.zola360.com; истекает = вторник, 14 ноября 2034 г. 01:34:25 GMT; путь =/; HttpOnly, 47=0; домен =.zola360.com; путь =/, UserId=47; домен =.zola360.com; путь =/"
И просто вставка значения ss-pid в ss-id работает:
cookie = "ss-id = ss-PID-сеанс-cookie; домен =.zola360.com; путь = /; HttpOnly, ss-pid = ss-PID-сеанс-cookie; домен =.zola360.com; истекает = вторник, 14 ноября 2034 01:34:25 GMT; путь =/; HttpOnly, ss-opt=perm; домен =.zola360.com; срок действия = вт, 14 ноября 2034 01:34:25 GMT; путь =/; HttpOnly, X-UAId=; домен =.zola360.com; истекает = вторник, 14 ноября 2034 г. 01:34:25 GMT; путь =/; HttpOnly, 47=0; домен =.zola360.com; путь =/, UserId=47; домен =.zola360.com; путь =/"
И скрипт 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-id, даже если ss-opt = perm.
1 ответ
При аутентификации с GET /api2/auth?username=user&password=...
оно отправлено с вашим постоянным cookie ss-pid
т.е.
Cookie: ss-pid=P2hslABCmSs7pomRqNz5; ss-opt=perm; X-UAId=
rememberme=true
опция говорит ServiceStack поддерживать сеанс пользователей против постоянного ss-pid
печенье. Эта опция поддерживается пользователями ss-opt=perm
cookie, который HTTP-ответ сообщает клиенту добавить:
Set-Cookie: ss-opt=perm; domain=.zola360.com; expires=Mon, 13-Nov-2034 16:11:09 GMT; - path=/; HttpOnly
Хотя это и не важно в этом случае, так как временная сессия ss-id
ServiceStack указывает клиенту добавить новый запрос с помощью:
Set-Cookie: ss-id=pojZkNAdMcEcACDREcRM; domain=.zola360.com; path=/; HttpOnly
Вопрос с последующим запросом GET /api2/auth
где клиент не пересылает ss-pid
cookie, он изначально аутентифицирован с помощью (т.е. P2hslABCmSs7pomRqNz5
против cvgslABCmSs6pomYdLu0
):
Cookie: ss-pid=cvgslABCmSs6pomYdLu0; ss-opt=perm; X-UAId=; ss-id=lYWZkFAdMcZcABCDcRM; 47=0; UserId=47
Какой ServiceStack не знает (т.е. не поддерживает сессию против), поэтому он возвращается с 401 Not Authenticated
как и ожидалось.
HTTP-клиент должен быть настроен для повторной отправки файлов cookie
Не ясно, какой HTTP-клиент вы используете, но он должен быть настроен на повторную отправку файлов cookie, что обычно является поведением по умолчанию. Аякс отправит как постоянный ss-pid
печенье и временные ss-id
только для этого сеанса браузера, например, временный ss-id
cookie будет удален, когда браузер будет закрыт, а новый запрос получит новый ss-id
печенье.
С помощью клиентов службы C# он только повторно отправляет постоянные файлы 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
Экземпляр может быть использован для доступа к защищенной записи несколько раз, как показано в этом Auth Test:
for (int i = 0; i < 500; i++)
{
var response = client.Send<SecureResponse>(new Secured { Name = "test" });
Console.WriteLine("loop : {0}", i);
}